Last active
November 29, 2017 20:22
-
-
Save jazzedge/cd2cbdea68eb23ee4c726e936e75720a to your computer and use it in GitHub Desktop.
In this example, we are going to update many records. Let’s take a look at the case of a dictionary App. We have our local copy of the data, but when the user downloads the App from the App Store and launches it for the first time, it is possible that some of the records from the initial set of data have become outdated. The technique we are goi…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 01 - 04. See: https://www.invasivecode.com/weblog/advanced-cloudkit-ii | |
| 05. See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/ | |
| 01. In the first method, we create a query with a predicate to fetch the records. | |
| We create a CKQueryOperation and pass it to the second method, along with the operation | |
| queue that we will use to execute it. | |
| func updateWordDefinitionChanges() { | |
| // Create the initial query | |
| let predicate = NSPredicate(format: "TRUEPREDICATE") | |
| let query = CKQuery(recordType: "WordDefinitions", predicate: predicate) | |
| // Create the initial query operation | |
| let queryOperation = CKQueryOperation(query: query) | |
| let operationQueue = NSOperationQueue() | |
| self.executeQueryOperation(queryOperation, onOperationQueue: operationQueue) | |
| } | |
| 02. In the second method we setup the query: | |
| - we assign the database where it will be executed; | |
| - we set a block that will be executed for each record found, where we will process the | |
| changes and update the local copy of the data; | |
| - we set a completion handler that will be executed when the operation finishes; | |
| - we add the operation to the operation queue to execute it. | |
| func executeQueryOperation(queryOperation: CKQueryOperation, onOperationQueue operationQueue: NSOperationQueue) { | |
| let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase; | |
| // Setup the query operation | |
| queryOperation.database = publicDatabase | |
| // Assign a record process handler | |
| queryOperation.recordFetchedBlock = { (record : CKRecord) -> Void in | |
| // Process each record | |
| self.updateWordDefinitionWithIdentifier(record.recordID.recordName) | |
| } | |
| 03. In the queryCompletionBlock, as you can see in the source code, you should handle | |
| any errors that may occur (see our previous post on CloudKit). Note that we are checking | |
| if a CKQueryCursor is provided. If it exists, that indicates that there are more results | |
| to fetch (because the operations are limited in size and number of records). | |
| If so, we use the cursor to initialize a new query operation and we use the same | |
| method to setup and execute it. This ensures that we will create and execute serialized | |
| query operations until we finally process all the records. | |
| // Assign a completion handler | |
| queryOperation.queryCompletionBlock = { (cursor: CKQueryCursor?, error: NSError?) -> Void in | |
| guard error==nil else { | |
| // Handle the error | |
| return | |
| } | |
| if let queryCursor = cursor { | |
| let queryCursorOperation = CKQueryOperation(cursor: queryCursor) | |
| self.executeQueryOperation(queryCursorOperation, onOperationQueue: operationQueue) | |
| } | |
| } | |
| // Add the operation to the operation queue to execute it | |
| operationQueue.addOperation(queryOperation) | |
| } | |
| //05. From www.whatmatrix.com | |
| Fetching a record by name is very straightforward. You can think of the name as the primary | |
| key of the record in a simple database sense (names must be unique, for example). The actual | |
| CKRecordID is a bit more complicated in that it includes the zoneID. | |
| The CKFetchRecordsOperation operates on one or more records at a time. In this example, | |
| there’s just the one record, but for future expandability, this is a great potential | |
| performance benefit. | |
| // Fetch a record from the iCloud database | |
| public func loadRecord(name: String, completion: @escaping (CKRecord?, Error?) -> Void) { | |
| let recordID = CKRecordID(recordName: name, zoneID: self.zoneID!) | |
| let operation = CKFetchRecordsOperation(recordIDs: [recordID]) | |
| operation.fetchRecordsCompletionBlock = { records, error in | |
| guard error == nil else { | |
| completion(nil, error) | |
| return | |
| } | |
| guard let noteRecord = records?[recordID] else { | |
| // Didn't get the record we asked about? | |
| // This shouldn’t happen but we’ll be defensive. | |
| completion(nil, CKError.unknownItem as? Error) | |
| return | |
| } | |
| completion(noteRecord, nil) | |
| } | |
| operation.qualityOfService = .utility | |
| let container = CKContainer.default() | |
| let db = container.privateCloudDatabase | |
| db.add(operation) | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment