首页 > 解决方案 > 无法通过 recordName UUID 查询单个 CloudKit 记录

问题描述

我有一个CloudKit应用程序,其中记录本地存储在CoreData. 创建CoreData记录时,UUID会生成 a 并将其填充到系统 recordName 字段中。该应用程序创建并保存记录,CoreData然后将记录上传到CloudKit. 这工作正常。

但是,我现在正在编码以修改记录,并且无法通过 recordName UUID 获取记录。我没有成功设置谓词来仅搜索该记录。我可以检索所有记录,也可以从我在记录类型TRUEPREDICATE中创建的字段中检索单个记录。我创建了一个名为 myRecordName 的字段,其中存储了与recordNameCloudKit相同的 UUID 。CloudKit使用 myRecordName 的查询可以正常工作。

我在下面展示了谓词的三种方法。如果 p1 和 p2 都没有被注释掉,则应用程序在运行时崩溃。我想我在这里遗漏了一些非常简单的东西。任何指导将不胜感激。Xcode 10.2.1,iOS 12.2,在真机上测试。

如果 p1 或 p2 或两者都没有被注释掉,控制台会显示:

*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[CKReference rangeOfString:]: unrecognized selector sent to instance 0x280878520”

func queryDatabase() {

    let recordZone = CKRecordZone(zoneName: "PrimaryZone")
    let recName = "0E763775-5AD3-4A50-BFB8-AC310180E8A2"

    let recID = CKRecord.ID(recordName: recName, zoneID: recordZone.zoneID)
    let searchRecord = CKRecord(recordType: "Patient", recordID: recID)

    let p1 = NSPredicate(format: "%K == %@", CKRecord.Reference(recordID: recID, action: CKRecord_Reference_Action.none))
    let p2 = NSPredicate(format: "%K == %@", CKRecord.Reference(record: searchRecord, action: CKRecord_Reference_Action.none))

    //let predicate = NSPredicate(format: "TRUEPREDICATE")
    let p3 = NSPredicate(format: "myRecordName = %@", recName)

    let query = CKQuery(recordType: "Patient", predicate: p3)
    let sortDescriptor = NSSortDescriptor(key: "lastNameText", ascending: true)
    query.sortDescriptors = [sortDescriptor]

    privateDatabase.perform(query, inZoneWith: recordZone.zoneID) { (results, error) in
        if error != nil {
            print("error querying database\(String(describing: error?.localizedDescription))")
        } else {

            DVC.ckRecords = results!
            //print(results!)
            print(DVC.ckRecords.first!)

        }//if error else
    }//perform query block

}//queryDatabase

标签: iosswiftcore-datacloudkit

解决方案


我从未使用过 CloudKit,所以也许我错了,但是……</p>

两个问题代码行p1=p2=尝试NSPredicate使用格式字符串创建一个。每个格式字符串都包含两个 var arg 替换,也就是占位符:%K%@. 因此,要使其正常工作,该格式字符串参数必须后跟另外两个参数:第一个是键路径,应该是字符串 (%K),第二个是其值的对象 (%@)。出于您的目的,关键路径可能只是一个属性名称。

但是您只提供了另外一个参数,一个CKRecord.Reference对象,系统会尝试为第一个(属性名称,字符串)参数解析该对象。您得到的错误是系统尝试解析对象时发生的典型情况,例如CKRecord.Reference当它期待一个字符串时。Swift 可能是相当安全的类型,但老式的 NSPredicate var args 函数不是:)

要解决这个问题(并继续下一个问题),您应该提供关键路径(参数名称)参数,如下所示:

let p1 = NSPredicate(format: "%K == %@", "recordID", CKRecord.Reference(recordID: recID, action: CKRecord_Reference_Action.none))
let p2 = NSPredicate(format: "%K == %@", "recordID", CKRecord.Reference(record: searchRecord, action: CKRecord_Reference_Action.none))

由于我不完全了解您在做什么,您可能需要稍微调整这两行。但关键是,给定您的格式字符串,您需要三个参数NSPredicate(format:),而中间的参数需要是一个表示键路径或属性名称的字符串。


推荐阅读