2015-02-09 7 views
10

Ich habe zur Zeit Wolkenjunge bekam in meiner App so einrichten, dass ich einen neuen Rekord bin Zugabe unter Verwendung der Hilfe des folgenden Codes,CloudKit: Alle Datensätze mit einem bestimmten Datensatztyp abrufen?

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]; 

Aber jetzt würde ich ALL holen zu können, wie Datensätze mit dem gleichen Datensatztyp "Strings" und geben diese in einem NSArray kompiliert zurück. Wie würde ich das machen? Derzeit habe ich nur herausgefunden, wie man jeden Datensatz einzeln mit einer RecordID abruft, was mühsam ist, da muss es einen einfacheren Weg geben.

[_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"]);    
    } 
}]; 
+0

Nach CKQuery API-Referenz: „Prädikate basieren Sie können keine Wert- oder blockbasierten Prädikate verwenden. " Ich glaube nicht, dass es immer so war, aber momentan ist keine der beiden Antworten korrekt, weil sie 'NSPredicate (value:)' –

+0

@JamesLingo verwenden. Hast du es versucht? ist es eine Vermutung? 'NSPredicate (value: true)' ist völlig in Ordnung –

+0

Ich habe es in der Vergangenheit verwendet, aber jeder, der es tut, sollte wissen, dass es nicht für CloudKit unterstützt wird, laut Apples eigener Dokumentation. Apple könnte sehr wohl Änderungen vornehmen, die diesen Code kaputt machen würden, und es kann ohne Wert oder blockbasierte Prädikate gemacht werden. –

Antwort

8

Aaaand, ich habe es. Mit dem folgenden Code konnte ich eine Abfrage erstellen, die in der Datenbank ausgeführt wird, um dann ein NSArray im Abschlussblock zurückzugeben, den ich durchforstete, und den Wert für den gespeicherten Schlüssel in einem NSLog zurückgab.

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"]); 
    } 
}]; 
+1

dies wird jedoch nicht alle Datensätze zurückgeben eine Teilmenge (in der Regel standardmäßig auf 100 begrenzt) –

+0

@MaxDesiatov was meinst du mit begrenzt? Wie man alles holt? – Ryde

+0

Macht nichts, es (100 Grenze) wird hier beantwortet: [link] (http://stackoverflow.com/questions/29592964/ckquery-from-private-zone-returns-only-first-100-ckrecords-from-in (cloudkit) und [link] (http://stackoverflow.com/questions/27728115/limit-the-amount-of-results-returned-in-cloudkit) – Ryde

0

Die followig Funktion werden alle Datensätze für die angeforderte Datensatztyp zurück:

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) 
    } 
} 
2

Hier ist die Antwort in 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     
     } 
    } 
} 
0

Lösung für Swift 4, zeigt, wie alle Datensätze vom Typ "Yourtable" holen, auch druckt System Field und 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 ?? "")") 
    }) 
}