【问题标题】:iOS15: NSPersistentCloudKitContainer: how to un-share objects?iOS15:NSPersistentCloudKitContainer:如何取消共享对象?
【发布时间】:2021-10-06 18:28:45
【问题描述】:

我正在开发一个应用程序,该应用程序使用 NSPersistentCloudKitContainer 在 iOS 15 中使用新的共享支持。我没有办法告诉 Core Data 一个对象或一组对象不再共享。

例如,如果我创建了一组对象,然后调用 share(_:to:completion:),则这些对象将正确共享并按预期移动到新的自定义 CKRecordZone

现在,如果用户停止使用 UICloudSharingController 共享对象,Core Data 创建的 CKShare 会从 CloudKit 中正确删除,但对象仍在自定义区域中,Core Data 仍然具有原始的 @987654327 @ 与那些对象相关联。所以,当我打电话给fetchShares(matching:) 时,我仍然得到CKShare,但当然,这不再有效。过去,使用我自己的代码,我会使用UISharingControllers 委托来获得用户停止共享的通知,然后更新我的模型。但似乎没有办法告诉 Core Data 这一变化。

通过将应用程序移至后台然后再前台,或者通过停止应用程序并重新启动来强制 Core Data 获取 CloudKit 更改不会导致 Core Data 注意到对共享的更改。

有谁知道如何告诉 Core Data 这些对象不再共享?

【问题讨论】:

  • 向 Apple 提交了反馈。希望我们将来能找到一些方法来做到这一点。与此同时,我不得不在我的应用程序中实现一些变通方法。我不喜欢它们,但它们工作得很好。
  • 你是不是偶然使用了CKModifyRecordsOperation
  • 不,我仍然使用UICloudSharingController 来停止分享。但是要检查是否共享记录(以便我可以更新 UI),而不是依赖来自 fetchShares(matching:)CKShare 的存在,我从该方法获取共享的 url,并调用 CKContainer.shareMetadata(for: url) 来验证共享实际上存在于 CloudKit 中。我将写更多关于我所做的事情,希望能帮助别人。当前的实现有很多“陷阱”。
  • 我问是因为它从过时的文档中显示,以前可能是这样完成的? developer.apple.com/documentation/cloudkit/shared_records/…
  • 是的,如果您想使用自己的代码手动删除共享,就是这样做的。但是,当用户选择“停止共享”时,UICloudSharingController 会为您执行此操作。

标签: ios core-data cloudkit


【解决方案1】:

我通过始终检查共享是否确实存在于 CloudKit 中来解决此问题,而不是依赖来自 fetchShares(matching:)CKShare 的存在。我从 CKShare 返回的 fetchShares(matching:) 得到 URL 并调用它:

private func remoteShare(at url: URL) async throws -> CKShare? {
        do {
            let metadata = try await cloudKitContainer.shareMetadata(for: url)
            return metadata.share
        } catch let error as CKError {
            if error.retryable {
                throw RemoteError.retryable
            } else if error.userInterventionRequiredError {
                throw RemoteError.userInterventionRequired
            } else if error.code == .unknownItem {
                return nil
            } else {
                throw RemoteError.remoteFailure
            }
        } catch {
            throw RemoteError.remoteFailure
        }
    }
}

如果我得到unknownItem,这意味着遥控器上没有共享,因此该对象实际上并未共享。

RemoteError 是我的自定义错误处理,我在CKError 上有一些扩展来对错误进行分类。

【讨论】:

    【解决方案2】:

    该问题的另一个解决方法是创建共享对象的副本,然后删除原始对象。它并不优雅,但它同时有效。 (希望 Apple 会在某个时候通过更好的解决方案解决这个问题。) 副本将像您共享原始文件之前一样放置在默认区域中。你会留下一个空的共享区域,但我通过在应用启动时运行一个后台任务来处理这个问题,该任务会删除所有空的共享区域,所以它不会失控。

    我还没有尝试过 Dharman 发布的解决方案,但我想它比查询本地缓存要慢。使用上述方法,您仍然可以使用演示应用程序中的“isShared”代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多