Skip to content

Instantly share code, notes, and snippets.

View jazzedge's full-sized avatar

Rocco Labellarte jazzedge

View GitHub Profile
@jazzedge
jazzedge / Swift - CloudKit - Pre-populate a database
Last active November 29, 2017 18:25
To populate our database of word definition changes, we are going to create a record for each of the word definitions that have changed and save it in iCloud using CloudKit. This time we are talking about lots of records, so doing it manually on the CloudKit dashboard is not the best solution. So, we are going to create another App, a Mac App, t…
See: https://www.invasivecode.com/weblog/advanced-cloudkit-ii
01. In your project, create a new target and choose a Mac App.
We need to enable CloudKit, as we did with our iOS App.
Select the target that you have just created and follow the same steps,
going to the Capabilities pane and switching on iCloud, and activating
the CloudKit checkbox. This time we want to have access to the iCloud
OS App and select its checkbox.
02. Now we are ready to create a CKRecord for each of our word definitions.
@jazzedge
jazzedge / Swift - CloudKit - Fetching Multiple Records
Last active November 29, 2017 20:22
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…
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() {
@jazzedge
jazzedge / Swift - CloudKit Subscriptions - 1
Last active November 30, 2017 06:05
We do not want to wait for the next time the user launches the App, and we do not want to be fetching the record each time if it has not changed. Instead, we want to minimize the fetches that we make to CloudKit, and only fire a fetch if the record has actually changed. So, how do we do that? The answer is using CloudKit subscriptions.
See: https://www.invasivecode.com/weblog/advanced-cloudkit-i
01. Now when the App launches, instead of directly performing a fetch to CloudKit, what we are going to do first is to check if we have already subscribed to the record changes. If we are subscribed we do not need to do anything else, as we will be notified by CloudKit via remote push notifications. If we are still not subscribed (for example, the first time the user uses the App), before subscribing, we will need to perform a fetch of the record, to be sure that we have the most updated version of the data. Then, we will check if the user has an iCloud account available. In this case, we need an iCloud account to be available, because we are going to save the subscription on CloudKit, and therefore we need write permissions. If the iCloud account is available, we can create a subscription and save it on the public database. The subscription is setup to be fired anytime the record changes.
Let’s add this new method to our AppDelegate and call it w
@jazzedge
jazzedge / Swift - CloudKit: Update App Settings
Last active November 29, 2017 20:28
In this example, we will solve the case of having to update a setting of the App, like the server URL and its API key.
See: https://www.invasivecode.com/weblog/advanced-cloudkit-i
01. To access the schema of the database, click on the button CloudKit Dashboard, or
go to https://icloud.developer.apple.com/dashboard. In the CloudKit dashboard, you
can manage the schema of the database, create new Record Types, and add, edit and delete records.
02. Select Record Types and then click on the + button to create a new record type.
Name the new record type WebServiceSettings. Then, add two fields of type string.
Call them serviceURL and serviceAPIKey. By default, when you create new fields,
indexes are added, to allow sorting, querying and searching on them. In this case,
@jazzedge
jazzedge / Swift - CloudKit: Save & Handle Error examples
Last active November 29, 2017 18:12
All calls to the CloudKit API could fail. If any operation cannot be performed, you will receive an error instead of the data. This error can have extra information in the userInfo dictionary that can help you make the correct decision to recover from it.
See for example 1:https://www.invasivecode.com/weblog/advanced-cloudkit-i
See for example 2: https://stackoverflow.com/questions/44023936/cloudkit-full-and-complete-error-handling-example
01. Example 1
For example, if an operation cannot be performed because the service is unavailable, or you
have exceeded the rate limits, there will be an entry in the dictionary for the key
CKErrorRetryAfterKey. Its value is a NSNumber containing the number of seconds after
you should retry the request:
@jazzedge
jazzedge / Swift - CloudKit - Fetch Add Save Delete multiple records
Last active November 30, 2017 04:34
If you have necessity to manage many record at the same time you can create a CKModifyRecordsOperation, which allows you to add/save/delete all records at once.
01. Save and Delete Records at the same time
let recordsToSave: [CKRecord] ...
let recordIDsToDelete: [CKRecordID] ...
let saveRecordsOperation = CKModifyRecordsOperation(
recordsToSave: recordsToSave,
recordIDsToDelete: recordIDsToDelete
)
saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
// handle errors here
@jazzedge
jazzedge / Swift - CloudKit: Saving a single record
Last active November 29, 2017 20:28
Each record is represented by a CKRecord object. Once you have created a new record you can simply call saveRecord:completionHandler: on your CKDatabase object. CloudKit will connect to the Internet asynchronously when saveRecord method is invoked. If you are saving a previously retrieved entry, any changes will update the version stored on Clou…
01. Example of saving a single record
let privateDB = CKContainer.defaultContainer().privateCloudDatabase
let record = CKRecord(recordType: “Employee”)
record.setObject(“John”, forKey: “name”)
record.setObject(“Stephens Green West, Dublin 2, Dublin”, forKey: “address”)
privateDB.saveRecord(record) { savedRecord, error in
// handle errors here
}
@jazzedge
jazzedge / Swift - CloudKit: Fetching Records
Last active November 30, 2017 04:36
There are two main ways of accessing records in CloudKit: Fetching individual records by record ID or using a query with a predicate to get a list of records. In order to fetch records by identifier you need to create a CKRecordID object and then call the fetchRecordWithID: method. In order to fetch records by predate you have to create an NSPre…
01. Using a query with a predicate to get a list of records.
let privateDB = CKContainer.defaultContainer().privateCloudDatabase
let predicate = NSPredicate(format: "firstName = %@", "John")
let query = CKQuery(recordType: "Artist", predicate: predicate)
privateDB.performQuery(query, inZoneWithID: nil) { records, error in
guard let records = records else { return }
//Use the records..
}
CKContainer.defaultContainer().accountStatusWithCompletionHandler{ status, error in
guard status == .Available else { return }
//The user’s iCloud account is available..
}
@jazzedge
jazzedge / Swift - CloudKit Error Helper Function and Extension
Last active November 30, 2017 06:13
CloudKit provides a full range of error codes, with accompanying information, to allow developers to handle various edge cases and, where necessary, provide detailed explanations to the user about possible issues. Also, several CloudKit operations can return an error as a single error value or a compound error signified at the top level as parti…
01. See:https://stackoverflow.com/questions/43553969/handling-cloudkit-errors
02. See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/
03. See CloudKit error codes: https://developer.apple.com/documentation/cloudkit/ckerrorcode
04. https://stackoverflow.com/questions/44023936/cloudkit-full-and-complete-error-handling-example
01. Helper function to manage CloudKit Errors
import Foundation
import CloudKit