标签: cloudkit

寻找 Core Data 到 CloudKit 公共数据库同步以及删除和订阅工作的工作示例

经过多天的尝试但没有成功后,我在这里发布这个问题,希望有人可以帮助我解决这个看起来相当简单的问题。我正在为Swift项目而不是SwiftUI执行此操作。

我的要求非常简单,我很困惑为什么苹果的文档或其他任何地方都没有明确的解决方案。我希望在我的 iOS 应用程序上有一个从 CloudKit 同步到应用程序核心数据的公共和私有数据库,反之亦然。

我已经看过 WWDC 视频和示例代码好几次了。如果他们在工作,我就不会在这里发布我的问题。

最新 WWDC2022 视频中的人正在展示 WWDC2019 视频中的代码。而且您下载的代码与他在视频中显示的代码不同。对于这样一个简单的任务来说,这个下载的代码不仅过于复杂和混乱,而且它也不处理公共数据库同步和/或订阅。苹果的教程工作太糟糕了。

经过一番努力,我也设法找到了 WWDC2019 代码,但它无法在较新的 Xcode 上编译。我正在使用 Xcode 13。我将其修复为可在 Xcode 上运行。但最终,它并没有按预期与 CloudKit 同步。

我查阅了无数的例子,但它们都已经过时了。我还没有看到一个显示最新 CloudKit 屏幕的示例。大多数示例仅讨论私有数据库同步,这是一个相当简单且直接的过程。几乎没有任何示例谈论设置订阅,更不用说公共数据库了。通过订阅设置公共数据库的唯一示例位于 Hacking With Swift 网站,但它没有讨论将 Core Data 与 CloudKit 同步,而是直接从 CloudKit 中保存和读取。

Apple 自己的示例也仅适用于私有数据库同步。

经过许多天的挣扎和挫折,我来到这里。我从各种示例中精心挑选了工作代码片段。但最终我没能让事情顺利进行。

我在下面发布我的代码。当在设备上运行时,它会在 CloudKit 上创建记录。它也应该创建订阅,但并不是每次都创建它们。即使创建了订阅,它们也不会被可靠地触发。有时他们会被解雇,有时则不会。这是CloudKit的开发环境的问题吗?我尝试过设置多个 CloudKit 容器,但这个问题仍然存在。

此外,模拟器和真实设备上的行为并不相同。在 Simulator 上,我知道您不会收到推送通知,但即使启动应用程序也不会每次都从 CloudKit 下载记录。因此,有时它会按预期工作,而有时则根本不起作用。尽管日志不断显示它们与 CloudKit 后端正在进行某种通信。

无论如何,在 CloudKit 上删除记录并不会在设备上删除它。

运行 WWDC2022 视频提供的示例也非常不稳定。它应该创建帖子项目。它确实如此,但是无论我设置私有数据库订阅还是公共数据库订阅,同步工作都非常不可靠。删除了还是不行。通知也不起作用,尽管我在我的应用程序中设置得很好appdelegate

那么,有没有可行的解决方案可供参考?任何帮助将不胜感激。

lazy var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "PublicDB")
        
        let store = …
Run Code Online (Sandbox Code Playgroud)

database core-data ios swift cloudkit

5
推荐指数
1
解决办法
755
查看次数

如何在 SwiftUI 中从 PhotosPicker 获取照片 url?

我正在使用 PhotosPicker 让用户选择照片。如何检索所选照片的​​ URL?

我尝试打印 imageSelection.itemIdentifier 并得到可选(“03966B05-1F51-4A20-801C-B617A2BC14DB/L0/001”),我不知道这是否与网址路径有关。

这是我使用 PhotosPicker 的类,使用WWDC2022的示例代码。

class CreateViewModel: ObservableObject {
    @Published var post: Post = Post() // Record being added to CloudKit
    
    enum ImageState {
        case empty, loading(Progress), success(Image), failure(Error)
    }
    
    @Published private(set) var imageState: ImageState = .empty
    
    @Published var imageSelection: PhotosPickerItem? {
        didSet {
            if let imageSelection {
                let progress = loadTransferable(from: imageSelection)
                imageState = .loading(progress)
            } else {
                imageState = .empty
            }
        }
    }

    // Load asset data using transferable
    private func …
Run Code Online (Sandbox Code Playgroud)

url photo cloudkit swiftui

5
推荐指数
1
解决办法
1814
查看次数

使用 CloudKit 时 SwiftData 模型的独特属性

不幸的是,使用 CloudKit 时,该.unique属性不可用于 SwiftData 模型属性。是否有最佳实践为我自己的模型设置这样的约束?

对于本地数据库,在创建和插入新模型之前获取(和过滤)模型是相当简单的。

但是如何防止来自其他设备的模型重复 - 即,在从 CloudKit 导入时将重复的模型与本地现有的模型合并,然后将它们插入到本地 SwiftData DB 中?

cloudkit swift-data

5
推荐指数
1
解决办法
241
查看次数

CKFetchRecordChangesOperation-moreComing

changesOperation.fetchRecordChangesCompletionBlock = ^(CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData, NSError *operationError){

    //encode and save token

    NSData *encodedServerChangeToken = [NSKeyedArchiver archivedDataWithRootObject:serverChangeToken];

    [[NSUserDefaults standardUserDefaults] setObject:encodedServerChangeToken forKey:fetchToken];

    [[NSUserDefaults standardUserDefaults] synchronize];



    //handle more - **this causes a retain cycle**
    if(changesOperation.moreComing){

    }

};
Run Code Online (Sandbox Code Playgroud)

嗨,您只是想知道在fetchRecordChangesCompletionBlock中,文档说:

如果服务器无法使用此操作对象传递所有更改的结果,则在执行fetchRecordChangesCompletionBlock属性中的块之前,将此属性设置为YES。要获取其余更改,请使用服务器返回的更改令牌创建一个新的CKFetchRecordChangesOperation对象。

在上面的代码中,这将导致一个保留周期,因此应如何处理?在重新创建操作时,是否可以使用已创建的相同完成块?

ios ios8 cloudkit

4
推荐指数
1
解决办法
1180
查看次数

CloudKit从当前用户获取所有订阅

我设法在Apples CloudKit中保存,更改和删除记录.我甚至收到订阅的通知,我不知道的是,我如何列出当前用户的所有订阅.

到目前为止,这是我的代码:

let operation = CKFetchSubscriptionsOperation()
operation.fetchSubscriptionCompletionBlock = { (d, e) -> Void in
    println("got subscription")
    if e != nil {
        println("Error")
        dump(e)
    }
    dump(d)
}
publicDatabase.addOperation(operation)
Run Code Online (Sandbox Code Playgroud)

我得到的是:

got subscription
Error
- <CKError 0x14db0ed0: "Invalid Arguments" (12)> #0
- 0 key/value pairs
Run Code Online (Sandbox Code Playgroud)

什么是无效参数?我如何获得所有已保存订阅的列表?

subscription ios swift cloudkit

4
推荐指数
1
解决办法
1555
查看次数

iOS Swift:在deleteRowsAtIndexPaths上崩溃

当我从tableView中删除一行时,我遇到了崩溃.不知道发生了什么事.这是我的代码:

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        let items = days[indexPath.row]
        self.removeItems(items, indexPath: indexPath)
    }

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return days.count
}
Run Code Online (Sandbox Code Playgroud)

为removeItems

func removeItems(items: [CKRecord], indexPath: NSIndexPath) {

    for item in items {
        db.deleteRecordWithID(item.recordID) { (record, error) -> Void in
            if error != nil {
                println(error.localizedDescription)
            }

            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                if let index = find(exercises, item) {
                    exercises.removeAtIndex(index)
                }
            }
        }
    }

    days.removeAtIndex(indexPath.row)
    tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
Run Code Online (Sandbox Code Playgroud)

uikit ios icloud swift cloudkit

4
推荐指数
1
解决办法
3626
查看次数

CloudKit:使用CKModifyRecordsOperation保存记录时出错

<CKError 0x14d8cb70: "Partial Failure" (2/1011); "Failed to modify some records"; partial errors: {
    B5DEF0B5-F064-4B27-9C89-BE75C9134297:(_defaultZone:__defaultOwner__) = <CKError 0x14d83b70: "Server Record Changed" (14/2037); "Error saving record <CKRecordID: 0x15748cd0; B5DEF0B5-F064-4B27-9C89-BE75C9134297:(_defaultZone:__defaultOwner__)> to server: Protection data didn't match">
}>
Run Code Online (Sandbox Code Playgroud)

当我尝试保存CKRecords 时,我收到此错误CloudKit.任何的想法?

我是否必须像在便捷API中那样获取第一条记录?

我正在使用CKModifyRecordsOperation方法来更新更多记录.

ios cloudkit

4
推荐指数
1
解决办法
2005
查看次数

使用CKReference与CKRecord的CloudKit性能

比方说,我有一个CKRecordrecordType帖子.帖子保留一些值,如标题和描述.当帖子显示在应用程序中时,它会附有编写它的用户的姓名和个人资料图片(让我们称之为Writer).我的问题是 - 最好将一个存储CKReference到Writer的配置文件中(配置文件是另一种包含Writer详细信息的记录),或者在写入时直接将Writer的详细信息添加到Post中会不会更好?

从数据库模式的角度来看,第一个选项非常有意义,但从性能角度来看,它似乎非常糟糕.在这个系统上有成千上万的用户,提取的数量和加载它们的时间似乎都是不合理的.

第一部分涉及加载所有帖子.

func loadPosts() {
    // ...Setup the query
    publicData.performQuery(query, inZoneWithID: nil) { (results: [CKRecord]?, error: NSError?) in
        if let posts = results {
            self.loadProfiles(posts)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

完成了一个查询,现在我们调用了 loadProfiles

func loadProfiles(posts: [CKRecord]) {
    // Get the reference IDs out of the Posts
    var referenceIDs = [CKRecordID]()
    for post in posts {
        // Get the reference from the post
        // Append the recordID to the referenceIDs array
    }

    // Perform the …
Run Code Online (Sandbox Code Playgroud)

schema ios swift cloudkit

4
推荐指数
1
解决办法
459
查看次数

调用服务器到服务器CloudKit Web服务时的授权错误

我正在尝试实施与CloudKit Web服务的一些基本集成,遵循Apple的身份验证请求指南.我已经按照一些帮助,这个这个问题,就是如何正确授权的请求,并且似乎是正确的以下所有步骤,但我仍然得到401 AUTHENTICATION_FAILED苹果错误.

我定位的端点是一个POST端点,用于在给定记录名称的情况下检索记录.

我在我的代码中添加了注释,以显示我在不同阶段获得的输出,并且我使用了替代证书,因此我没有提供我的正版私钥:

def self.signature(parameters, date, image_id)
    #date: 2016-08-14T14:32:20Z

    #parameters: {"records":[{"recordName":"7DBC4FAD-D18C-476A-89FB-14A515098F34"}]}

    encoded_parameters = Digest::SHA256.base64digest(parameters)

    #encoded_parameters: 6gmJ4AvmJgkNY4SJm6ImOxZaZ07J7cih/tRXI0zkRjQ=

    url_subpath = CloudKit.url_subpath

    #url_subpath: /database/1/iCloud.ProjectDent.TwIM/development/public/records/lookup

    message = date + ':' + encoded_parameters + ':' + url_subpath

    #message: 2016-08-14T14:23:35Z:6gmJ4AvmJgkNY4SJm6ImOxZaZ07J7cih/tRXI0zkRjQ=:/database/1/iCloud.ProjectDent.TwIM/development/public/records/lookup

    private_key = OpenSSL::PKey.read(File.read('altkey.pem'))

    signature = private_key.dsa_sign_asn1(OpenSSL::Digest::SHA256.digest(message))

    #signature: -? WX?xfc???????,????v?3+Xt!?$R?_Y?×*?,?3??Z-\#????h

    encoded_signature = Base64.strict_encode64(signature)

    #encoded_signature: MEUCIFdYlHhmrxoIY8KW1tT6yZT17bYsP8ia09WTdpEzK1h0AiEA0yRSh39fWYHDlyqJLNgzhr9aLVwj2cWtkse3aA0tGZI=

    return encoded_signature
end

def self.headers(parameters, image_id)
    date = Time.now.utc.iso8601

    signature = self.signature(parameters, date, image_id)

    headers = {
        'X-Apple-CloudKit-Request-KeyID' => CloudKit.key_id, …
Run Code Online (Sandbox Code Playgroud)

ruby openssl ruby-on-rails cloudkit cloudkit-web-services

4
推荐指数
1
解决办法
217
查看次数

CloudKit - 哪个CKErrors应该作为.partialFailure处理,它们是否也应该作为非部分故障处理?

我已经构建了基本的CloudKit同步引擎并且正常工作,现在我正在充实我的错误处理.我想要一个全面的列表,列出了收到.partialFailure响应代码时每条记录可能出现的错误.

文档中有一个包含所有错误代码的列表,但在我的搜索中,对于我可能会在partialErrorsByItemID字典中显示哪些内容并且仅显示为错误代码(或者是他们可以同时出现,也许只发送一条记录?).

在Apple CloudKit Share代码示例中,有一个CloudKitError类来处理错误,并处理以下部分错误:

.serverRecordChanged
.zoneNotFound
.unknownItem
.batchRequestFailed
Run Code Online (Sandbox Code Playgroud)

但我不认为这是详尽无遗的,因为班级的其他人在处理不是.partialFailure的错误时并非详尽无遗.肯定.invalidArguments可能是部分失败错误?

这是我想我需要涵盖的内容:

.alreadyShared (if sharing)
.assetFileModified (if using Assets)
.assetFileNotFound (if using Assets)
.batchRequestFailed
.constraintViolation
.invalidArguments
.referenceViolation (if sharing)
.serverRecordChanged
.unknownItem
.zoneBusy?
.zoneNotFound
Run Code Online (Sandbox Code Playgroud)

最后,因为这些是作为部分错误处理的,我是否还需要处理它们作为CloudKit的错误代码响应,就像处理非部分错误代码(如.serviceUnavailable)一样?我没有使用CKDatabase便捷方法,我正在使用像CKModifyRecordsOperation这样的完整操作,如果这很重要?

提前致谢!

ios swift cloudkit

4
推荐指数
1
解决办法
278
查看次数