Skip to content

Instantly share code, notes, and snippets.

View jazzedge's full-sized avatar

Rocco Labellarte jazzedge

View GitHub Profile
In addition to data, CloudKit may also be used to store larger assets such as audio or video
files, large documents, binary data files or images. These assets are stored within CKAsset
instances. Assets can only be stored as part of a record and it is not possible to directly
store an asset in a cloud database. Once created, an asset is added to a record as just
another key-value field pair. The following code, for example, demonstrates the addition
of an image asset to a record:
let imageAsset = CKAsset(fileURL: imageURL)
let myRecord = CKRecord(recordType: "Vacations")
@jazzedge
jazzedge / Swift - CloudKit - Add Save Delete Multiple Records
Last active November 29, 2017 21:02
A group of record operations may be performed in a single transaction using the CKModifyRecordsOperation class.
See: http://www.techotopia.com/index.php/An_Introduction_to_CloudKit_Data_Storage_on_iOS_8
A group of record operations may be performed in a single transaction using the
CKModifyRecordsOperation class. This class also allows timeout durations to be specified for
the transaction, together with completion handlers to be called at various stages during the
process. The following code, for example, uses the CKModifyRecordsOperation class to add three
new records and delete two existing records in a single operation. The code also establishes
timeout parameters and implements all three completion handlers. Once the modify operation
object has been created and configured, it is added to the database for execution:
See: http://www.techotopia.com/index.php/An_iOS_8_CloudKit_Subscription_Example
01. Configure App for Remote Notifications
Before adding any code to the project, a couple of configuration changes need to be made to the project to add support for notifications. First, the Info.plist file needs to be updated to indicate that the app supports remote notifications when in the background. To add this setting, select the Info.plist file from the project navigator panel and add a new entry for the Required background modes key.
Once the key has been added, click on the right-facing arrow to the left of the key to unfold the values. In the value field for Item 0, enter remote-notification.
02. Registering an App to Receive Push Notifications
See:
The CloudKitNote Class
For starters, a few custom errors can be defined to shield the client from the internals of CloudKit, and a simple delegate protocol can inform the client of remote updates to the underlying Note data.
import CloudKit
enum CloudKitNoteError : Error {
case noteNotFound
@jazzedge
jazzedge / Swift - CloudKit - Handling Notification of Updated Records
Last active November 29, 2017 20:24
CloudKit Notifications provide the means to find out when records have been updated by another client.
See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/
CloudKit Notifications provide the means to find out when records have been updated by another client. However, network conditions and performance constraints can cause individual notifications to be dropped, or multiple notifications to intentionally coalesce into a single client notification. Since CloudKit’s notifications are built on top of the iOS notification system, you have to be on the lookout for these conditions.
However, CloudKit gives you the tools you need for this.
Rather than relying on individual notifications to give you detailed knowledge of what change an individual notification represents, you use a notification to simply indicate that something has changed, and then you can ask CloudKit what’s changed since the last time you asked. In my example, I do this by using CKFetchRecordZoneChangesOperation and CKServerChangeTokens. Change tokens can be thought of like a bookmark telling you wher
@jazzedge
jazzedge / Swift - CloudKit - Saving Records
Last active November 30, 2017 06:08
Saving records is, perhaps, the most complicated operation.
See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/
Saving records is, perhaps, the most complicated operation. The simple act of writing a record to the database is straightforward enough, but in my example, with multiple clients, this is where you’ll face the potential issue of handling a conflict when multiple clients attempt to write to the server concurrently. Thankfully, CloudKit is explicitly designed to handle this condition. It rejects specific requests with enough error context in the response to allow each client to make a local, enlightened decision about how to resolve the conflict.
Although this adds complexity to the client, it’s ultimately a far better solution than having Apple come up with one of a few server-side mechanisms for conflict resolution.
The app designer is always in the best position to define rules for these situations, which can include everything from context-aware automatic merging to user-directed resolution instructions. I
@jazzedge
jazzedge / Swift - CloudKit Subscriptions - 4
Last active November 30, 2017 06:02
Subscriptions are one of the most valuable CloudKit features. They build on Apple’s notification infrastructure to allow various clients to get push notifications when certain CloudKit changes occur.
See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/
Subscriptions are one of the most valuable CloudKit features. They build on Apple’s notification infrastructure to allow various clients to get push notifications when certain CloudKit changes occur. These can be normal push notifications familiar to iOS users (such as sound, banner, or badge), or in CloudKit, they can be a special class of notification called silent pushes. These silent pushes happen entirely without user visibility or interaction, and as a result, don’t require the user to enable push notification for your app, saving you many potential user-experience headaches as an app developer.
The way to enable these silent notifications is to set the shouldSendContentAvailable property on the CKNotificationInfo instance, while leaving all of the traditional notification settings (shouldBadge, soundName, and so on) unset.
Note also, I am using a CKQuerySubscription with a very simple “always true” pre
@jazzedge
jazzedge / Swift - CloudKit - Creating a Custom Zone
Created November 29, 2017 20:18
CloudKit automatically creates a default zone for the private database. However, you can get more functionality if you use a custom zone, most notably, support for fetching incremental record changes.
See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/
Since this is a first example of using an operation, here are a couple of general observations:
First, all CloudKit operations have custom completion closures (and many have intermediate closures,
depending on the operation). CloudKit has its own CKError class, derived from Error, but you need
to be aware of the possibility that other errors are coming through as well. Finally, one of the
most important aspects of any operation is the qualityOfService value. Due to network latency,
airplane mode, and such, CloudKit will internally handle retries and such for operations at a
qualityOfService of “utility” or lower. Depending on the context, you may wish to assign a higher
@jazzedge
jazzedge / Swift - CloudKit Low Level Operation Constructs
Last active November 29, 2017 20:18
Apple provides two levels of functionality in the CloudKit SDK: High level “convenience” functions, such as fetch(), save(), and delete(), and lower level operation constructs with cumbersome names, such as CKModifyRecordsOperation. The convenience API is much more accessible, while the operation approach can be a bit intimidating. However, Appl…
See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/
The CloudKitNoteDatabase Singleton
CloudKit operations provide superior control over the details of how CloudKit does its work and,
perhaps more importantly, really force the developer to think carefully about network behaviors
central to everything CloudKit does. For these reasons, I am using the operations in these code
examples.
Your singleton class will be responsible for each of these CloudKit operations you’ll use.
@jazzedge
jazzedge / Swift - CloudKit Subscriptions - 3
Last active November 30, 2017 06:04
We will learn how to use subscriptions so that we will be notified when the data changes in CloudKit. With subscriptions you can track changes as they are occurring on the server.
See: https://www.invasivecode.com/weblog/advanced-cloudkit-part-iii
01. Each time a change occurs, a remote push notification will be sent to the device. This notification includes the recordID of the changed record together with the database (public or private) and the reason that the push notification was trigged. There are three possible reasons that could have triggered the notification: a record has changed, a new record has been added, or an existing record has been deleted. When you create a subscription you have to specify which record type you want to track and the reason (creation, deletion or change). This is an example of how you would create a subscription in Swift:
func subscribeToWordDefinitionChanges() {
let predicate = NSPredicate(format: "TRUEPREDICATE")
let subscription = CKSubscription(recordType: "WordDefinitions", predicate: predicate, options: [.FiresOnRecordCreation, .FiresOnRecordUpdate, .FiresOnRecordDeletion])
let publicDatabase = CKContainer.defaultContainer().publicC