问题 CloudKit:获取具有特定记录类型的所有记录?


我现在有 CloudKit 在我的应用程序中设置,以便我使用以下代码的帮助添加新记录,

CKRecordID *recordID = [[CKRecordID alloc] initWithRecordName:@"stringArray"];
CKRecord *record = [[CKRecord alloc] initWithRecordType:@"Strings" recordID:recordID];
[record setObject:[NSArray arrayWithObjects:@"one", @"two", @"three", @"four", nil] forKey:@"stringArray"];
[_privateDatabase saveRecord:record completionHandler:nil];

但是,现在我希望能够获取具有相同记录类型的所有记录“Strings”,并将这些记录返回到NSArray中。我该怎么做呢?目前,我所知道的是如何使用recordID单独获取每条记录,这是一个麻烦,必须有一个更简单的方法。

[_privateDatabase fetchRecordWithID:recordID completionHandler:^(CKRecord *record, NSError *error) {
   if (error) {
      // Error handling for failed fetch from private database
   }
   else {
      NSLog(@"ICLOUD TEST: %@", [record objectForKey:@"stringArray"]);            
  }
}];

11653
2018-02-09 04:32


起源

根据CKQuery API Reference:“Predicates基于格式字符串。您不能使用值或基于块的谓词。”我不认为它总是这样,但目前两个答案都不正确,因为他们使用 NSPredicate(value:) - Mercutio
@JamesLingo你试过吗?这是假设吗? NSPredicate(value: true) 完全没问题 - Andrea Mugnaini
我过去曾经使用它,但根据Apple自己的文档,任何这样做的人都应该知道它不支持CloudKit。 Apple可以很好地进行会破坏该代码的更改,并且可以使用基于值或基于块的谓词来完成。 - Mercutio
我认为它类似于通过哈希值识别枚举。您可以逃脱它,直到声明订单发生变化并且您的代码中断...基本上,制造商包含有关如何使用其api等的手册,这是有原因的...... - Mercutio


答案:


Aaaand,我知道了。使用下面的代码,我能够创建一个在数据库上运行的查询,然后在完成块中返回一个NSArray,我循环访问,并在NSLog中返回已保存密钥的值。

NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Strings" predicate:predicate];

[_privateDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
    for (CKRecord *record in results) {
        NSLog(@"Contents: %@", [record objectForKey:@"stringArray"]);
    }
}];

8
2018-02-09 04:50



这不会返回所有记录,只是一个子集(默认情况下通常限制为100) - Max Desiatov
@MaxDesiatov你的意思是有限的吗?如何取得所有? - Ryde
没关系,它(100限制)在这里得到解答: 链接 和 链接 - Ryde
不起作用。获取错误:<CKError 0x13de5ffc0:“无效参数”(12/2015); server message =“Field'___recordID'未标记为可查询” - Jonny
修复就在这里 stackoverflow.com/a/29142836/129202 - Jonny


这是Swift 3.0中的答案。

func myQuery()  {
    let predicate = NSPredicate(value: true)
    let query = CKQuery(recordType: "tableName", predicate: predicate)

    publicDatabase.perform(query, inZoneWith: nil) { (record, error) in

        for record: CKRecord in record! {
            //...

            // if you want to access a certain 'field'.
            let name = record.value(forKeyPath: "Name") as! String                
        }
    }
}

2
2017-08-23 14:55





解决方案 斯威夫特4, 显示如何获取“YourTable”类型的所有记录,也打印 System Field 和 Custom Field

let query = CKQuery(recordType: "YourTable", predicate: NSPredicate(value: true))
CKContainer.default().publicCloudDatabase.perform(query, inZoneWith: nil) { (records, error) in
  records?.forEach({ (record) in

    // System Field from property
    let recordName_fromProperty = record.recordID.recordName
    print("System Field, recordName: \(recordName_fromProperty)")

    // Custom Field from key path (eg: deeplink)
    let deeplink = record.value(forKey: "deeplink")
    print("Custom Field, deeplink: \(deeplink ?? "")")
  })
}

2
2018-01-15 03:37





followig函数将返回所请求记录类型的所有记录:

let database = CKContainer(identifier: "container_here").privateCloudDatabase
typealias RecordsErrorHandler = ([CKRecord], Swift.Error?) -> Void

func fetchRecords(forType type: String, completion: RecordsErrorHandler? = nil) {

    var records = [CKRecord]()

    let query = CKQuery(recordType: type, predicate: NSPredicate(value: true))
    let queryOperation = CKQueryOperation(query: query)
    queryOperation.zoneID = CloudAssistant.shared.zone.zoneID

    queryOperation.recordFetchedBlock = { record in
        records.append(record)
    }

    queryOperation.queryCompletionBlock = { cursor, error in

        self.fetchRecords(with: cursor, error: error, records: records) { records in
            completion?(records, nil)
        }
    }

    database.add(queryOperation)
}

private func fetchRecords(with cursor: CKQueryCursor?, error: Swift.Error?, records: [CKRecord], completion: RecordsHandler?) {

    var currentRecords = records

    if let cursor = cursor, error == nil {

        let queryOperation = CKQueryOperation(cursor: cursor)

        queryOperation.recordFetchedBlock = { record in
            currentRecords.append(record)
        }

        queryOperation.queryCompletionBlock = { cursor, error in
            self.fetchRecords(with: cursor, error: error, records: currentRecords, completion: completion)
        }

        database.add(queryOperation)

    } else {
        completion?(records)
    }
}

0
2018-05-10 11:34