CloudKit Quick Start

CloudKit Quick Start
Contents
About This Document 5
See Also 6
Enabling CloudKit in Your App 7
About Containers and Databases 7
Setup 8
Enable iCloud and Select CloudKit 9
Access CloudKit Dashboard 10
Share Containers Between Apps 11
Add Containers to an App 11
Create Custom Containers 13
Verify Your Steps 14
Create an iCloud Account for Development 15
Recap 15
Creating a Database Schema by Saving Records 16
About Designing Your Schema 16
Separate Data into Record Types 16
Decide on Names for Your Records 18
Create Records 18
Save Records 19
Enter iCloud Credentials Before Running Your App 20
Alert the User to Enter iCloud Credentials 22
Run Your App 22
Verify Your Steps 22
View Record Types by Using CloudKit Dashboard 23
Enable Metadata ID Indexes 24
View Records Using CloudKit Dashboard 24
Recap 25
Using CloudKit Dashboard to Manage Databases 26
About the Development and Production Environments 26
Select Your Container 27
Reset the Development Environment 28
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
2
Contents
Create and Delete Record Types 28
Add, Modify, and Delete Records 30
Search Records 31
Sort Records 32
Recap 33
Fetching Records 34
Fetch Records by Identifier 34
Fetch and Modify Records 34
Query for Records Using Predicates 35
Recap 36
Using Asset and Location Fields 38
Store Large Files in CloudKit 38
Verify Your Steps 39
Add Location Fields 39
Verify Your Steps 40
Fetch Records by Location 40
Recap 42
Adding Reference Fields 43
About Modeling Relationships in Your Schema 43
Create Reference Fields 45
Verify Your Steps 46
Fetch Records with Reference Fields 47
Resolve One-To-One Relationships 47
Resolve One-To-Many Relationships 48
Batch Operations to Save and Fetch Multiple Records 49
Specify Ownership to Automatically Delete Related Records 51
Subscribing to Record Changes 52
Save Subscriptions to the Database 52
Verify Your Steps 54
Register for Push Notifications 55
Handle Push Notifications in Code 56
Test Subscriptions 57
Recap 57
Testing Your CloudKit App 58
Distribute Your iOS App Using Ad Hoc Provisioning 58
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
3
Contents
Distribute Your Mac App Using the Team Provisioning Profile 60
Recap 60
Deploying the Schema 62
Deploy the Development Schema to Production 62
Verify Your Steps 63
Promote the Development Schema Changes to Production 65
Disable Unused Indexes 65
Assign Roles to Other Team Members 67
Recap 68
Document Revision History 69
Glossary 70
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
4
About This Document
Important: This is a preliminary document for an API or technology in development. Apple is supplying
this information to help you plan for the adoption of the technologies and programming interfaces described
herein for use on Apple-branded products. This information is subject to change, and software implemented
according to this document should be tested with final operating system software and final documentation.
Newer versions of this document may be provided with future betas of the API or technology.
This document gets you started creating a CloudKit app that stores structured app and user data in iCloud.
Using CloudKit, instances of your app—launched by different users on different devices—have access to the
records stored in the app’s database. Use CloudKit if you have model objects that you want to persist and share
between multiple apps running on multiple devices. These model objects are stored as records in the database
and can be provided by you or authored by the user.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
5
About This Document
See Also
You’ll learn how to:
●
Enable CloudKit in your Xcode project and create a schema programmatically or with CloudKit Dashboard
●
Fetch records and subscribe to changes in your code
●
Use field types that are optimized for large data files and location data
●
Subscribe to record changes to improve performance
●
Test your CloudKit app on multiple devices before uploading it to the App Store or Mac App Store
●
Deploy the schema to production and keep it current with each release of your app
See Glossary (page 70) for the definition of database terms used in this book.
See Also
The following WWDC sessions provide more CloudKit architecture and API details:
●
WWDC 2014: Introducing CloudKit introduces the basic architecture and APIs used to save and fetch records.
●
WWDC 2014: Advanced CloudKit covers topics such as private data, custom record zones, ensuring data
integrity, and effectively modeling your data.
The following documents provide more information about related topics:
●
Designing for CloudKit in iCloud Design Guide provides an overview of CloudKit.
●
App Distribution Quick Start teaches you how to provision your app for development and run your iOS
app on devices.
●
App Distribution Guide contains all the provisioning steps including configuring app services and submitting
your app to the App Store or Mac App Store.
●
Start Developing iOS Apps Today or Start Developing Mac Apps Today introduces you to Xcode and the
steps to create a basic app.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
6
Enabling CloudKit in Your App
CloudKit is an app service available only to apps distributed through the App Store and Mac App Store. CloudKit
requires additional configuration in your Xcode project. Your app must be provisioned and code signed to
access CloudKit. To avoid code signing issues, enable CloudKit using the Capabilities pane in Xcode. There
should be no need for you to edit entitlements directly in Xcode or Member Center.
About Containers and Databases
Multiple apps and users have access to iCloud, but data is segregated and encapsulated in partitions called
containers. The containers belonging to your apps cannot be accessed by apps from another developer.
However, your apps can share containers. Multiple apps can share the same container, and one app can use
multiple containers. There’s one default container per app, but you can create additional custom containers.
The identifier for the default container matches the app’s bundle ID. The other container IDs you specify need
to be unique across all developer accounts. Containers can’t be deleted.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
7
Enabling CloudKit in Your App
Setup
An app has access to both a public and private database in each container. The public database is for storing
user and app data that is shared between all instances of the app. By default, all users can read the public
database, but they need to enter iCloud credentials to write to the public database. There’s a private database
for each user of your app, but the app only has access to the private database of the current user. The user has
to enter iCloud credentials for the app to read and write to the private database.
Setup
To perform all the steps in this document, you need:
●
A Mac computer with Xcode 6 or later installed
●
For the best experience, the latest OS X and Xcode releases installed
●
An Xcode project that builds without errors
●
Membership in the Apple Developer Program
●
Permission to create code signing and provisioning assets in Member Center
Verify that you have performed these tasks before you begin using CloudKit. For step-by-step instructions,
read App Distribution Quick Start .
Task
Join the Apple Developer Program.
Create an Xcode project that builds and runs.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
8
Enabling CloudKit in Your App
Enable iCloud and Select CloudKit
Task
Add your Apple ID to Accounts preferences.
Create your team provisioning profile:
For Mac apps, choose Mac App Store as the signing
identity.
Select your team from the Team pop-up menu.
Click Fix Issue.
For Mac apps, enable App Sandbox in the Capabilities pane.
If you successfully complete the preceding tasks, the error message and Fix Issue button below the Team
pop-up menu in the General pane disappears. The screenshot below shows the General pane for an iOS app
when the code signing assets are successfully created.
To troubleshoot code signing and provisioning, read Troubleshooting in App Distribution Guide .
Enable iCloud and Select CloudKit
CloudKit is one of three app services provided by iCloud. The other iCloud app services—key-value storage
and iCloud documents—also appear in the iCloud settings in Xcode. To use CloudKit, you first enable iCloud
and then select the CloudKit service.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
9
Enabling CloudKit in Your App
Access CloudKit Dashboard
Important: When you select CloudKit, Xcode creates a default container ID based on the bundle ID. Because
you can’t delete iCloud containers, verify that your bundle ID is correct in the General pane in Xcode before
selecting CloudKit. To change your bundle ID, read Set the Bundle ID in App Distribution Quick Start .
To enable iCloud and select CloudKit
1.
In the Capabilities pane, select the switch in the iCloud row.
Xcode provisions your app to use iCloud. (Key-value storage is enabled by default.)
2.
Select the CloudKit checkbox.
Xcode creates a default CloudKit container based on the bundle ID and adds the CloudKit framework to
your project.
Your app can now store data and documents in iCloud.
Access CloudKit Dashboard
Use CloudKit Dashboard to manage your CloudKit container schema and records. The schema describes the
organization of records, fields, and relationships in a database. A record is an instance of a record type. In a
relational database, a record type corresponds to a table and a record corresponds to a row in a table.
To sign in to CloudKit Dashboard
1.
In the iCloud settings in the Capabilities pane, click CloudKit Dashboard.
Alternatively, go to https://icloud.developer.apple.com/dashboard.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
10
Enabling CloudKit in Your App
Share Containers Between Apps
2.
If necessary, enter your Apple ID credentials and click Sign In.
All the containers for all the teams you belong to appear in the container pop-up menu in the upper-left
corner of the window. The assets for the selected container (named Gallery in the screenshot) are displayed.
To sign out, choose Sign Out from the account pop-up menu (named Tom Clark in the screenshot) in the
upper-right corner of the window.
Share Containers Between Apps
Optionally, configure your app to use multiple containers or share a container with other apps. For example,
you might use one app internally to create record types and records programmatically to return a database
to a known state. This app needs to share the same container as the end-user app you are developing and
testing. To do this, you enable the first app to use the default container of the second app or create a custom
container that both apps share. iOS and Mac apps can also be configured to share the same containers.
Add Containers to an App
Select an existing container ID used by another app or create a new one.
To add a container to an app
1.
In the Capabilities pane under the iCloud settings, select “Specify custom containers.”
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
11
Enabling CloudKit in Your App
Share Containers Between Apps
When you previously selected the CloudKit service, Xcode created a default container ID for your app that
matches the bundle ID. A checkmark appears next to the default container ID.
2.
If necessary, click the Refresh button below the Containers table to download containers from Member
Center that are used by other apps.
3.
In the row of the container ID you want to add, select the checkbox.
Xcode updates the list of container IDs in the entitlements file.
The screenshot below shows the Curator and Gallery app sharing the Gallery app’s default container.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
12
Enabling CloudKit in Your App
Share Containers Between Apps
Create Custom Containers
Alternatively, create a custom container shared by multiple apps.
Important: Only team admins can create containers. If you are an individual, you are the team agent (with
admin privileges) for your one person team.
To create a custom container
1.
If "Use default container” is selected, select “Specify custom containers.”
2.
Click the Add button (+) at the bottom of the table.
3.
In the dialog that appears, enter an identifier for the container you want to add.
Warning: You can’t delete a container ID, so choose the container ID carefully.
A container ID begins with iCloud. followed by a string in reverse DNS notation, as in the
iCloud.com.example.gkumar1.SharedGallery container ID.
4.
Click OK.
Xcode adds the new container ID to the Xcode project entitlements file and to Member Center.
If you want to share the new container ID with another app, add the container to the app, as described in Add
Containers to an App (page 11).
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
13
Enabling CloudKit in Your App
Share Containers Between Apps
Verify Your Steps
You can view all the container IDs for your team in the iCloud settings or Member Center. In Member Center,
you can also add containers and edit the name of containers.
To view container IDs in Member Center
1.
In Member Center, select Certificates, Identifiers & Profiles.
2.
Under Identifiers, select iCloud Containers.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
14
Enabling CloudKit in Your App
Create an iCloud Account for Development
Create an iCloud Account for Development
You’ll need an iCloud account to save records to a CloudKit container. You’ll enter the credentials for this iCloud
account on the device that you run your app. If you don’t have an iCloud account, create one that you can use
during development. On your Mac, launch System Preferences and click iCloud. Click Create Apple ID under
the Apple ID text field and follow the instructions.
Recap
In this chapter, you learned how to:
●
Enable CloudKit in your Xcode project, which creates your app’s default container.
●
Access CloudKit Dashboard to view the container’s schema and records.
●
Create an iCloud account to use for development.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
15
Creating a Database Schema by Saving Records
During development, it’s easy to create a schema using CloudKit APIs. When you save record objects to a
database, the associated record types and their fields are automatically created for you. This feature is called
just-in-time schema and is available only when you use the development environment which is not accessible
by apps sold on the store. For example, during development you can populate a CloudKit database with test
records stored in a property list.
This chapter introduces some CloudKit APIs and contains code fragments. Add #import
<CloudKit/CloudKit.h> at the top of each implementation file that uses CloudKit classes and methods.
Read CloudKit Framework Reference for details on CloudKit APIs.
About Designing Your Schema
Design the CloudKit schema to store the portions of your app’s object model that you want to persist. If you
are implementing an app from scratch, use the Model-View-Controller design pattern to separate the user
interface views from the model objects. Then design a schema that efficiently stores the portions of the object
model you want to store in iCloud.
Separate Data into Record Types
A CloudKit schema consists of one or more record types that have a name, fields, and other metadata. The
field types are similar to the allowable property list types with some additions. Use a specialized Asset type
for bulk data that is stored separately from records, a Location type for efficiently querying geographical
coordinates, and a Reference type to represent one-to-one and one-to-many relationships among records.
The maximum size of a record is 1MB, so use the Asset type (not the Bytes type) for large data.
The table shows possible field types and their equivalent classes.
Field Type
Class
Description
Asset
CKAsset
A large file that is associated with a record but stored separately
Bytes
NSData
A wrapper for byte buffers that is stored with the record
Date/Time
NSDate
A single point in time
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
16
Creating a Database Schema by Saving Records
About Designing Your Schema
Field Type
Class
Description
Double
NSNumber
A double
Int(64)
NSNumber
An integer
Location
CLLocation
A geographical coordinate and altitude
Reference
CKReference
A relationship from one object to another
String
NSString
An immutable text string
List
NSArray
Arrays of any of the above field types
Design record types using these fields to store your app’s persistent data. For example, this sketch of a
master-detail user interface displays a collection of artwork titles in the master interface (column on the left)
and properties of the selected artwork in the detail interface (area on the right). The underlying object model
consists of an Artwork and Artist class where Artwork has a to-one relationship to Artist.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
17
Creating a Database Schema by Saving Records
Create Records
There’s a one-to-one mapping between the objects in this object model and the record types Artwork and
Artist. The artist field of the Artwork record type is a Reference type with a reference to an Artist
record. The image field is an Asset type containing a URL, and the location field is a Location type with
longitude and latitude properties. All other fields in Artwork and Artist are simple String and Date types.
Decide on Names for Your Records
Decide on a heuristic for creating unique names for your records. The record name coupled with a record zone
(a partition of a database) is the record identifier that represents the location of a record in a database. The
record name can be a foreign key used by another data source or a combination of strings that makes it unique
within a record zone. For example, the record name of an Artwork record can combine an artist’s first and
last name with a catalog number, as in the string 115 Chen, Mei. If you create records using CloudKit
Dashboard, a unique ID is automatically assigned to the record.
Create Records
First create a record identifier, an instance of the CKRecordID class, specifying the record name and record
zone. Then create a record, an instance of the CKRecord class, passing the record identifier. Set the record’s
fields using key-value coding style methods.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
18
Creating a Database Schema by Saving Records
Save Records
To create a record
1.
Create a record ID specifying a unique record name.
CKRecordID *artworkRecordID = [[CKRecordID alloc]
initWithRecordName:@"115"];
2.
Create a record object.
CKRecord *artworkRecord = [[CKRecord alloc] initWithRecordType:@"Artwork"
recordID:artworkRecordID];
3.
Set the record’s fields.
artworkRecord[@"title" ] = @"MacKerricher State Park";
artworkRecord[@"artist"] = @"Mei Chen";
artworkRecord[@"address"] = @"Fort Bragg, CA";
Save Records
First select a database where you will save the records (public, private, or custom) and then save the record.
If a record type doesn’t exist for the record, it is created for you.
To save a record
1.
Get the database in your app’s default container.
To get the public database:
CKContainer *myContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [myContainer publicCloudDatabase];
To get the private database:
CKContainer *myContainer = [CKContainer defaultContainer];
CKDatabase *privateDatabase = [myContainer privateCloudDatabase];
To get a custom container:
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
19
Creating a Database Schema by Saving Records
Enter iCloud Credentials Before Running Your App
CKContainer *myContainer = [CKContainer
containerWithIdentifier:@"iCloud.com.example.ajohnson.GalleryShared"];
To create a custom container shared by multiple apps, read Share Containers Between Apps (page 11).
2.
Save the record.
[publicDatabase saveRecord:artworkRecord completionHandler:^(CKRecord
*artworkRecord, NSError *error){
if (!error) {
// Insert successfully saved record code
}
else {
// Insert error handling
}
}];
If the record type doesn’t exist, CloudKit framework creates it with the fields you set.
Before clicking the Run button in Xcode, enter iCloud credentials on the device, as described in the next section.
Enter iCloud Credentials Before Running Your App
In production, the default permissions allow non-authenticated users to read records in the public database
but do not allow them to write records. Therefore, before you run your app and save records to the database,
enter an iCloud account in Settings on iOS or System Preferences on a Mac. Also enable iCloud Drive. Later,
write the necessary error handling to present a dialog to the user when iCloud credentials are needed, as
described in Alert the User to Enter iCloud Credentials (page 22).
In development, when you run your app through Xcode on iOS Simulator or an iOS device, you also need to
enter iCloud credentials to read records in the public database.
To run your app in iOS Simulator, enter the iCloud credentials in iOS Simulator before you select the simulator
and click the Run button in Xcode. You need to perform these steps for each iOS Simulator you select in the
Scheme pop-up menu in Xcode.
To enter iCloud credentials in iOS Simulator
1.
Choose Xcode > Open Developer Tool > iOS Simulator.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
20
Creating a Database Schema by Saving Records
Enter iCloud Credentials Before Running Your App
2.
In iOS Simulator, choose Hardware > Home .
3.
Launch the Settings app and click iCloud.
4.
Enter an Apple ID and password.
5.
Click Sign In.
Wait while iOS verifies the iCloud account.
6.
To enable iCloud Drive, click the iCloud Drive switch.
If the switch doesn’t appear, iCloud Drive is already enabled.
For how to create an iCloud account, read Create an iCloud Account for Development (page 15).
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
21
Creating a Database Schema by Saving Records
Alert the User to Enter iCloud Credentials
Alert the User to Enter iCloud Credentials
Before saving records, verify that the user is signed in to their iCloud account. If the user is not signed in, present
an alert instructing the user how to enter their iCloud credentials and enable iCloud Drive.
[[CKContainer defaultContainer] accountStatusWithCompletionHandler:^(CKAccountStatus
accountStatus, NSError *error) {
if (accountStatus == CKAccountStatusNoAccount) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Sign
in to iCloud"
message:@"Sign
in to your iCloud account to write records. On the Home screen, launch Settings,
tap iCloud, and enter your Apple ID. Turn iCloud Drive on. If you don't have an
iCloud account, tap Create a new Apple ID."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Okay"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
else {
// Insert your just-in-time schema code here
}
}];
To learn about errors that may occur when saving records, read CloudKit Framework Constants Reference .
Run Your App
In Xcode, run your app to execute the code that saves records and creates the schema in the database.
Verify Your Steps
Use CloudKit Dashboard to verify that the record types were added to the schema and that the records were
added to the database.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
22
Creating a Database Schema by Saving Records
Verify Your Steps
View Record Types by Using CloudKit Dashboard
Verify that the record types have the correct field names and types.
To view record types
1.
Sign in to CloudKit Dashboard.
2.
In the upper-left, choose the container used by your app from the pop-up menu.
If only one app is enabled to use CloudKit, the name of its default container appears, not the pop-up menu.
Warning: If the container ID doesn’t immediately appear in CloudKit Dashboard, try signing out
and signing in to CloudKit Dashboard again. If you just enabled CloudKit, it may take a moment
for the container to be created and appear in CloudKit Dashboard.
3.
In the left column, click Record Types.
The record types you added appear in the second column.
4.
In the second column, select a record type.
The field names and types appear in the detail area on the right.
The Users record type that appears is a reserved system record type that cannot be deleted, but you can
add fields to it.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
23
Creating a Database Schema by Saving Records
Verify Your Steps
Enable Metadata ID Indexes
All the metadata indexes for record types created using just-in-time schema are disabled by default. The record
ID query index needs to be enabled to view the associated records in CloudKit Dashboard.
To enable the record ID query index
1.
In the left column, click Record Types and select a record type.
2.
Click the index disclosure triangle under Metadata Indexes.
3.
Select the Query box in the ID row and click Save.
View Records Using CloudKit Dashboard
Verify that the records you saved have all the data.
To view records
1.
In the left column of CloudKit Dashboard, click Default Zone under Public Data or Private Data.
Records appear in the second column. (If you don’t use a custom zone, records are stored in the public
default zone.)
2.
In the second column, click a record.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
24
Creating a Database Schema by Saving Records
Recap
The record key-value pairs appear in the detail area on the right.
Recap
In this chapter you learned how to:
●
Create your schema by saving records programmatically
●
Share container IDs between multiple apps
●
Use CloudKit Dashboard to view the record types and records you created
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
25
Using CloudKit Dashboard to Manage Databases
You perform many database management tasks using CloudKit Dashboard. For example, you can modify both
the schema and records using CloudKit Dashboard. A container’s databases exist in both the development
and the production environment. The operations you can perform depend on whether you are in the
development or production environment.
Go to CloudKit Dashboard, sign in, and click the options in the left column to explore CloudKit Dashboard
features.
About the Development and Production Environments
The development environment is used to create a schema and add records for testing. The production
environment is accessed by apps sold on the App Store or Mac App Store. An app in development, can access
either the development or the production environment. However, an app sold on the store can access only
the production environment.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
26
Using CloudKit Dashboard to Manage Databases
Select Your Container
In the development environment, CloudKit automatically creates the schema for you based on the records
that you save to the database. This feature allows you to iterate and refine your schema without having to
explicitly create it. You can also use CloudKit Dashboard to modify the schema and add records.
The first time you deploy the schema, the schema is copied to the production environment (records are not
copied to the production environment). The next time you deploy the schema, the schema is merged with the
production schema. To prevent conflicts, you can’t delete fields or record types in a development schema that
were previously deployed to the production environment.
In the production environment, you can’t change the schema but you can add, modify, and delete records in
the public database.
When you run your CloudKit app through Xcode, it is automatically configured to use the development
environment. When you export your app from Xcode for testing, you specify either the development or
production environment. When you submit your app to the store, it is configured to use the production
environment.
Select Your Container
All of the functions in CloudKit Dashboard apply to the currently selected container. Switch the container using
the pop-up menu in the upper-left corner. CloudKit Dashboard displays all the containers belonging to all the
Apple Developer Program teams you belong to. Be sure to select the container used by the app that you are
developing before performing any of the tasks in this chapter.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
27
Using CloudKit Dashboard to Manage Databases
Reset the Development Environment
Reset the Development Environment
If you use just-in-time schema to populate a database with records, as described in Creating a Database Schema
by Saving Records (page 16), you can reset the development environment between runs of your app. If you
have never deployed your development environment, resetting the development environment deletes all the
records and record types. Otherwise, it deletes all the records and returns the schema to the state of the
production environment.
To reset the development environment
1.
In CloudKit Dashboard, click Deployment in the left column.
2.
Click Reset Development Environment.
3.
In the dialog that appears, read the warning, select the checkbox, and click Reset & Delete Data.
Create and Delete Record Types
In the development environment, you can create, modify, and delete record types using CloudKit Dashboard.
To create a record type
1.
In CloudKit Dashboard, click Record Types under Schema.
The schema’s record types appear in the second column.
2.
Click the Add button (+) in the upper-left corner of the detail area.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
28
Using CloudKit Dashboard to Manage Databases
Create and Delete Record Types
3.
Enter a name in the New Record Type field.
4.
Enter a field name, and select a field type from the pop-up menu.
5.
To add a field, click Add Field, enter a field name, and select a field type from the pop-up menu.
6.
To delete a field, click the Delete button (x) in the row of the field.
The Delete button appears when you hover over the row. If the field is deployed, the Delete button is
disabled.
7.
Click Save.
You can delete a record type only in the development environment and only when that record type is not
deployed. When you delete a record type, all its associated records are deleted from the database too.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
29
Using CloudKit Dashboard to Manage Databases
Add, Modify, and Delete Records
To delete a record type
1.
In CloudKit Dashboard, click Record Types under Schema.
The schema’s record types appear in the second column.
2.
Select the record type you want to delete.
3.
Click the trash icon in the upper-left corner of the detail area.
If the record type is deployed, the trash icon is disabled.
4.
In the dialog that appears, click Delete.
Add, Modify, and Delete Records
In the development and production environment, you can add, modify, and delete records in public databases
using CloudKit Dashboard.
To create a record
1.
In CloudKit Dashboard under Public Data or Private Data, click a zone.
For example, in the public database, click Default Zone. (The User Records zone contains records of type
Users created by CloudKit.)
2.
In the second column, choose the record type from the pop-up menu in the upper-left corner.
3.
In the detail area, click the Add button (+).
CloudKit Dashboard assigns a random UUID as the record ID.
4.
Enter values in the text fields.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
30
Using CloudKit Dashboard to Manage Databases
Search Records
5.
For Date/Time types, enter the calendar date and the time values in separate text fields.
6.
For Location types, enter the latitude and longitude in separate text fields.
The latitude ranges from -90 and 90, and longitude ranges from -180 to 180.
7.
For Asset values, drag the file to the box or click “Or Choose File” to upload the file.
8.
Click Save.
To view, modify, or delete a record
1.
In CloudKit Dashboard, click the zone under Public Data or Private Data.
2.
In the second column, choose the record type form the pop-up menu.
3.
Select the record you want to view, edit, or delete.
The record fields appear in the detail area.
4.
To edit a record, enter new values in the text fields and click Save.
5.
To delete a record, click the trash icon in the upper-left corner of the detail area and in the dialog that
appears, click Delete.
Search Records
In the development and production environment, you can search for records that have string fields.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
31
Using CloudKit Dashboard to Manage Databases
Sort Records
To search for records
1.
In the left column of CloudKit Dashboard, click Default Zone under Public Data or Private Data.
Records appear in the second column.
2.
In the second column, click the search icon.
A search field appears.
3.
Enter text in the search field.
CloudKit Dashboard sorts the records by the field values. If the record type doesn’t have a searchable field,
“… doesn’t have a searchable field.” appears below the search field.
Sort Records
In the development and production environment, you can sort records by field.
To search for records
1.
In the left column of CloudKit Dashboard, click Default Zone under Public Data or Private Data.
Records appear in the second column.
2.
In the second column, click a record.
3.
From the “Sort by address” pop-up menu, select a field.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
32
Using CloudKit Dashboard to Manage Databases
Recap
CloudKit Dashboard sorts the records by the field values.
Recap
This chapter introduces you to managing your databases with CloudKit Dashboard. You learned how to:
●
Reset the development environment to a known state
●
Create and delete record types
●
Create and edit records
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
33
Fetching Records
After you save records to the database, you can retrieve them using different mechanisms. Fetch individual
records by record ID, or query for many records using a predicate. (A predicate defines logical conditions for
searching for records.) Typically, you fetch a subset of records to display to the user at launch and then subscribe
to changes that interest the user.
If you use the Location field type, you can also fetch records within a geographical region, as described in
Fetch Records by Location (page 40).
Fetch Records by Identifier
If you know the record IDs for the records you want to fetch, then you can fetch by individual record ID. For
example, this code fragment fetches a record named 115.
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"115"];
[publicDatabase fetchRecordWithID:artworkRecordID completionHandler:^(CKRecord
*artworkRecord, NSError *error) {
if (error) {
// Error handling for failed fetch from public database
}
else {
// Display the fetched record
}
}];
Fetch and Modify Records
You can fetch, modify, and save changes you make to individual records. This code fragment fetches an Artwork
record, changes its date field value, and saves it to the database.
// Fetch the record from the database
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
34
Fetching Records
Query for Records Using Predicates
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"115"];
[publicDatabase fetchRecordWithID:artworkRecordID completionHandler:^(CKRecord
*artworkRecord, NSError *error) {
if (error) {
// Error handling for failed fetch from public database
}
else {
// Modify the record and save it to the database
NSDate *date = artworkRecord[@"date"];
artworkRecord[@"date"] = [date dateByAddingTimeInterval:30.0 * 60.0];
[publicDatabase saveRecord:artworkRecord completionHandler:^(CKRecord
*savedRecord, NSError *saveError) {
// Error handling for failed save to public database
}];
}
}];
Query for Records Using Predicates
If you have many records and store large files in iCloud, it is unlikely that you want to store all the records
locally on a device. Instead you fetch a slice of the data using a query. A query combines a record type, a
predicate, and a sort descriptor where the predicate contains fields that are indexed. You build a query in code
using a CKQuery object.
For example, this code fragment fetches all artwork with the specified title.
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title = %@", @"Santa
Cruz Mountains"];
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Artwork" predicate:predicate];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray
*results, NSError *error) {
if (error) {
// Error handling for failed fetch from public database
}
else {
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
35
Fetching Records
Recap
// Display the fetched records
}
}];
In the Gallery app, the artwork with the specified title is fetched.
Recap
In this chapter you learned how to:
●
Fetch records by identifier
●
Fetch, modify, and save individual records
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
36
Fetching Records
Recap
●
Fetch multiple records using a query and predicate
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
37
Using Asset and Location Fields
CloudKit provides field types specifically for storing large data files and for fetching records by location. Use
these data types to leverage the performance improvements that CloudKit provides for this type of data. You
can also fetch records by location. For example, display records on a map in a user-defined region.
Store Large Files in CloudKit
You can store large data files in CloudKit using the Asset field type. Assets are owned by the associated record,
and CloudKit handles garbage collection for you. CloudKit also efficiently uploads and downloads assets.
In code, the Asset field type is represented by a CKAsset object. This code fragment sets an Asset field in
an Artwork record to a resource file.
// Create a URL to the local file
NSURL *resourceURL = [NSURL fileURLWithPath:@"…"];
if (resourceURL){
CKAsset *asset = [[CKAsset alloc] initWithFileURL:resourceURL];
artworkRecord[@"image"] = asset;
}
When the record is saved, the file is uploaded to iCloud.
Add similar code that saves a record type with an Asset field to your app and run it. To save the record, read
Save Records (page 19).
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
38
Using Asset and Location Fields
Add Location Fields
Verify Your Steps
To verify that your changes to the schema and records were saved to iCloud, read View Record Types by Using
CloudKit Dashboard (page 23) and View Records Using CloudKit Dashboard (page 24). When you view records
with an Asset object, CloudKit Dashboard displays the size of the binary data. Optionally, download or remove
the binary data from the record.
Add Location Fields
If your record has an address or other location data, you can save it as a CLLocation object in the record and
later fetch records by location. For example, your app might display pins representing the records on a map.
This code fragment uses the CLGeocoder class to convert a string address to a location object and stores it
in a record.
CLGeocoder *geocoder = [CLGeocoder new];
[geocoder geocodeAddressString:artwork[kArtworkAddressKey]
completionHandler:^(NSArray *placemark, NSError *error){
if (!error) {
if (placemark.count > 0){
CLPlacemark *placement = placemark[0];
artworkRecord[kArtworkLocationKey] = placement.location;
}
}
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
39
Using Asset and Location Fields
Fetch Records by Location
else {
// insert error handling here
}
// Save the record to the database
}];
Add similar code that saves a record type with an Location field to your app and run it. To save the record,
read Save Records (page 19).
Verify Your Steps
When you view records in CloudKit Dashboard, it displays the longitude and latitude of the location field.
Fetch Records by Location
Once you have location data in your database, you can fetch records by location using a query containing a
record type, a predicate, and a sort descriptor. The Location field specified in the predicate must be indexed
for the fetch to work. (Fields are indexed by default.)
This code fragment fetches all records whose locations are within 100,000 meters of San Francisco.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
40
Using Asset and Location Fields
Fetch Records by Location
// Get the public database object
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
// Create a predicate to retrieve records within a radius of the user's location
CLLocation *fixedLocation = [[CLLocation alloc] initWithLatitude:37.7749300
longitude:-122.4194200];
CGFloat radius = 100000; // meters
NSPredicate *predicate = [NSPredicate
predicateWithFormat:@"distanceToLocation:fromLocation:(location, %@) < %f",
fixedLocation, radius];
// Create a query using the predicate
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Artwork" predicate:predicate];
// Execute the query
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray
*results, NSError *error) {
if (error) {
// Error handling for failed fetch from public database
}
else {
// Display the fetched records
}
}];
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
41
Using Asset and Location Fields
Recap
In this iOS app, artwork within the specified radius of a fixed location is fetched.
To learn more about locations and maps, read Location and Maps Programming Guide .
Recap
In this chapter you learned how to:
●
Add an Asset type to a record type by adding a CKAsset field to a record and saving the record
●
Add a Location type to a record type using a CLLocation object
●
Fetch objects by location
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
42
Adding Reference Fields
Use reference fields in your schema to represent relationships between model objects; for example, to represent
hierarchical data or indicate ownership. This chapter describes how to add references to records, to save and
fetch records with references, and to specify ownership so related records are automatically deleted.
About Modeling Relationships in Your Schema
You can use reference field types to represent both one-to-one and one-to-many relationships between your
model objects. In your code, a reference field is a CKReference object that encapsulates the record ID for a
target record and is added to the source record. To represent a one-to-one relationship in your schema, add
a reference field to the source record type.
To represent a one-to-many relationship between your model objects, it is more efficient if the reference is
from the child record to the parent record—that is, add a reference field to the child record. The child record
is the source, and the parent record is the target in this schema.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
43
Adding Reference Fields
About Modeling Relationships in Your Schema
For example, there’s a one-to-many relationship between the Artist and Artwork models and an inverse
one-to-one relationship from the Artwork to Artist model.
To represent these relationships in the schema, add a reference field to the corresponding Artwork record
type called artist. This reference field will contain the record ID of an Artist record.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
44
Adding Reference Fields
Create Reference Fields
Similarly, to represent the one-to-many relationship from Artist to Collection in the object model, add a
reference field to the Collection record. After you fetch these records, you create the appropriate one-to-one
and one-to-many relationships between the model objects.
Create Reference Fields
During development, save records containing reference fields to generate the schema. Represent a one-to-one
relationship in your schema by adding a CKReference object to the source record.
To create a reference from one record to another
1.
Create or get the record ID for the target record.
CKRecordID *artistRecordID = [[CKRecordID alloc] initWithRecordName:@"Mei
Chen"];
2.
Create a reference object by passing the target’s record ID as a parameter.
CKReference *artistReference = [[CKReference alloc]
initWithRecordID:artistRecordID action:CKReferenceActionNone];
3.
Add the reference object to the source record.
CKRecord *artworkRecord;
…
artworkRecord[@"artist"] = artistReference;
Save the source record to create the record type, as described in Creating a Database Schema by Saving
Records (page 16). If you want to save multiple records containing references between them, save all the
records in one operation, as described in Use a Single Operation to Save and Fetch Multiple Records (page
49). CloudKit will ensure that target records are saved before source records.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
45
Adding Reference Fields
Create Reference Fields
Verify Your Steps
In CloudKit Dashboard, view the record types, as described in View Record Types by Using CloudKit
Dashboard (page 23). A reference field should appear in the source record type. For example, the artist
field in the Artwork record type appears as a Reference field type.
View the records, as described in View Records Using CloudKit Dashboard (page 24). The target record name
should appear in the source record.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
46
Adding Reference Fields
Fetch Records with Reference Fields
Fetch Records with Reference Fields
Don’t use records (CKRecord objects) as your model objects in the Model-View-Controller design pattern.
Instead, create separate model objects from fetched records, especially when the fetched records contain
references. Your app is responsible for interpreting the references between records and creating the appropriate
relationships between model objects. Target records are not automatically fetched when the source record is
fetched. Your app is responsible for fetching target records as needed. There are different ways to fetch target
and source records depending on the type of relationship the reference represents.
If possible, batch fetches to resolve relationships between model objects, as described in Batch Operations to
Save and Fetch Multiple Records (page 49).
Resolve One-To-One Relationships
For one-to-one relationships, get the reference field from the source record and fetch the associated target
record.
To fetch the target of a one-to-one relationship
1.
Get the reference field.
CKRecord *artworkRecord;
…
CKReference *referenceToArtist = artworkRecord[@"artist"];
2.
Get the target record ID from the reference.
CKRecordID *artistRecordID = artistReference.recordID;
3.
Fetch the target record.
[publicDatabase fetchRecordWithID:artistRecordID
completionHandler:^(CKRecord *artistRecord, NSError *error) {
if (error) {
// Failed to fetch record
}
else {
// Successfully fetched record
}
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
47
Adding Reference Fields
Fetch Records with Reference Fields
}];
Add your code to the fetchRecordWithID:completionHandler: completion handler parameter. For
example, add code to create the one-to-one relationship between the corresponding Artwork and Artist
objects.
Resolve One-To-Many Relationships
For one-to-many relationships, fetch all the children of a parent record at once using a predicate. You can fetch
all records that have the parent as its target record.
To fetch children of a one-to-many relationship
1.
Start with the parent record ID (CKRecordID) that you previously fetched and the model object for the
parent.
For example, create an Artist model object from an Artist record.
__block Artist *artist = [[Artist alloc] initWithRecord:artistRecord];
Use __block so that you can access the parent object in the completion handler later.
2.
Create a predicate object to fetch the child records.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@“artist = %@”,
artistRecordID];
In your code, replace artist with the name of the reference field in the child record, and replace
artistRecordID with the parent record ID.
Note: Possible values for the right-hand expression in the predicate format string parameter
include CKRecord, CKRecordID, and CKReference objects.
3.
Create a query object specifying the record type to search.
CKQuery *query = [[CKQuery alloc] initWithRecordType:@“Artwork”
predicate:predicate];
In your code, replace @“Artwork” with the name of the child record type.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
48
Adding Reference Fields
Batch Operations to Save and Fetch Multiple Records
4.
Perform the fetch.
CKDatabase *publicDatabase = [[CKContainer defaultContainer]
publicCloudDatabase];
[publicDatabase performQuery:query inZoneWithID:nil
completionHandler:^(NSArray *results, NSError *error) {
if (error) {
// Failed to fetch children of parent
}
else {
// Create model objects for each child and set the one-to-many
relationship from the parent to its children
}
}];
Add the code to the else statement that creates the corresponding relationships between your model
objects.
Batch Operations to Save and Fetch Multiple Records
It is more efficient to batch saves and fetches of multiple records into a single operation. This is especially
important if the record types contain reference fields. You can save new source and target records in one
operation using a CKModifyRecordsOperation object. You can create a reference to a target record that
doesn’t have an identifier. As long as you save both the source and target records together, CloudKit ensures
that in a graph of related CKRecord objects, target records are saved before source records. You can also fetch
all the targets of a set of source records in one operation using a CKFetchRecordsOperation object.
To fetch multiple records in a single operation
1.
Add all the record IDs for the records you want to fetch to an array.
For example, to fetch multiple one-to-one relationships, add all the target record IDs of the reference fields
to an array.
2.
Create the fetch record operation object by passing the array of record IDs as a parameter.
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation
alloc] initWithRecordIDs:fetchRecordIDs];
3.
Optionally, provide a per record completion handler.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
49
Adding Reference Fields
Batch Operations to Save and Fetch Multiple Records
If you want to save the data from successful individual records, provide a per record completion handler.
The completion handler should create a model object for a successfully fetched record, and because the
operation may fail, should keep the record ID of a failed fetch.
fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record,
CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Create a model object and set any relationships to other models
}
};
4.
Set the completion handler for the entire operation.
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary
*recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
}
else {
// Update all associated views
}
};
If you save the record IDs in the per record completion handler in step 3, you can attempt to fetch failed
records again.
5.
Start the operation.
fetchRecordsOperation.database = [[CKContainer defaultContainer]
publicCloudDatabase];
[fetchRecordsOperation start];
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
50
Adding Reference Fields
Specify Ownership to Automatically Delete Related Records
Specify Ownership to Automatically Delete Related Records
You can specify whether a source record of a reference is deleted when its target record is deleted. For example,
you may want the children of a one-to-many relationship to be deleted when the parent is deleted. The parent
record owns the children records. If the children own other records, they will also be deleted, causing a cascade
of deletions.
You specify the delete action when you create the reference object. To delete a source record when the target
is deleted, pass the target record and CKReferenceActionDeleteSelf as the action parameter to the
initWithRecord:action: method. In the Gallery sample, specify that artwork belonging to an artist should
be deleted when the artist is deleted.
CKReference *referenceToArtist = [[CKReference alloc] initWithRecord:artistRecord
action:CKReferenceActionDeleteSelf];
artworkRecord[@"artist"] = referenceToArtist;
Alternatively, check the DeleteSelf box in CloudKit Dashboard for each record.
CloudKit deletes the source record when the first target record of a CKReferenceActionDeleteSelf
reference is deleted. If a source record has multiple CKReferenceActionDeleteSelf references, it may be
deleted even though some of its other target records exist, leading to an inconsistent data model. Try to design
your schema so that each record has no more than one CKReferenceActionDeleteSelf reference.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
51
Subscribing to Record Changes
It’s inefficient for your app to repeat a query when the results are mostly the same as the last query. Instead,
subscribe to record changes, and let the server run the query in the background. The server will notify your
app of changes that interest the user or app. For example, if one user of your app is interested in artwork by
a certain artist, your app can be notified when new artwork by that artist is uploaded.
Save Subscriptions to the Database
In your code, create a subscription object specifying the record type, predicate, and types of changes you want
to be notified about. Then save the subscription object to the database.
To create and save a subscription
1.
Create a predicate object.
For example, subscribe to artwork from an artist (where the artist field in the Artwork record type is
a Reference type).
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
52
Subscribing to Record Changes
Save Subscriptions to the Database
CKRecordID *artistRecordID = [[CKRecordID alloc] initWithRecordName:@"Mei
Chen"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"artist = %@",
artistRecordID];
Note: Possible values for the right-hand expression in the predicate format string parameter
include CKRecord, CKRecordID, and CKReference objects. If you know the record name, you
can create a record ID containing just the record name.
2.
Create a subscription specifying the record type, predicate, and notification options.
CKSubscription *subscription = [[CKSubscription alloc]
initWithRecordType:@"Artwork"
predicate:predicate
options:CKSubscriptionOptionsFiresOnRecordCreation];
The possible values for the options parameter are: CKSubscriptionOptionsFiresOnRecordCreation,
CKSubscriptionOptionsFiresOnRecordDeletion,
CKSubscriptionOptionsFiresOnRecordUpdate, and CKSubscriptionOptionsFiresOnce. Because
the options parameter is a bitmask, you can subscribe to any combination of the type of changes. For
example, you can pass CKSubscriptionOptionsFiresOnRecordCreation |
CKSubscriptionOptionsFiresOnRecordUpdate as the options: parameter to receive notification
of all new data.
3.
Create a CloudKit notification object.
CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
notificationInfo.alertLocalizationKey = @"New artwork by your favorite
artist.";
notificationInfo.shouldBadge = YES;
To display a localized string to the user, set the notification’s alertLocalizationKey property (not the
alertBody property).
4.
Set the subscription’s notification object to the new CloudKit notification object.
subscription.notificationInfo = notificationInfo;
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
53
Subscribing to Record Changes
Save Subscriptions to the Database
5.
Save the subscription to the database.
CKDatabase *publicDatabase = [[CKContainer defaultContainer]
publicCloudDatabase];
[publicDatabase saveSubscription:subscription
completionHandler:^(CKSubscription *subscription,
NSError *error) {
if (error)
// insert error handling
}
];
In Xcode, run your app to save the subscription to the database.
Verify Your Steps
Verify that the subscription was saved to the schema. In CloudKit Dashboard, the subscription object appears
as a subscription type in the schema.
1.
In CloudKit Dashboard, choose the container used by your app from the pop-up menu in the upper-left
corner.
2.
Under Schema, click Subscription Types.
The subscriptions appear in the second column.
3.
If necessary, select a subscription.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
54
Subscribing to Record Changes
Register for Push Notifications
The subscription properties appear in the detail area.
Register for Push Notifications
Saving subscriptions to the database doesn’t automatically configure your app to receive subscription
notifications. CloudKit uses the Apple Push Notification service (APNs) (page 70) to send subscription
notifications to your app, so your app needs to register for push notifications to receive them.
For iOS apps, add this code to the application:didFinishLaunchingWithOptions: protocol method
to register for push notifications:
// Register for push notifications
UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings
settingsForTypes:UIUserNotificationTypeAlert categories:nil];
[application registerUserNotificationSettings:notificationSettings];
[application registerForRemoteNotifications];
For Mac apps, implement the applicationDidFinishLaunching: protocol method to register for push
notifications.
For both iOS and Mac apps, optionally implement the
application:didRegisterForRemoteNotificationsWithDeviceToken: and
application:didFailToRegisterForRemoteNotificationsWithError: methods to take the
appropriate action when the app successfully or unsuccessfully registers for push notifications.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
55
Subscribing to Record Changes
Handle Push Notifications in Code
Note: You don’t need to enable push notifications for the app’s explicit App ID in Member Center
to receive subscription notifications. Xcode automatically adds the APNs entitlement to your
entitlement file when you enable CloudKit.
Handle Push Notifications in Code
Next, implement the application:didReceiveRemoteNotification: method to process subscription
notifications when they arrive. For iOS apps, implement the UIApplicationDelegate protocol method and
for Mac apps, implement the NSApplicationDelegate protocol method. For example, implement this
method to update views when records matching your predicate are created, updated, or deleted.
1.
Add the application:didReceiveRemoteNotification: protocol method to the app’s delegate.
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
}
2.
In the application:didReceiveRemoteNotification: method, convert the userInfo parameter
to aCKNotification object.
CKNotification *cloudKitNotification = [CKNotification
notificationFromRemoteNotificationDictionary:userInfo];
3.
Get the body of the notification.
NSString *alertBody = cloudKitNotification.alertBody;
4.
Get the new or modified record from the CKQueryNotification object.
if (cloudKitNotification.notificationType == CKNotificationTypeQuery) {
CKRecordID *recordID = [(CKQueryNotification *)cloudKitNotification
recordID];
}
5.
Update views or notify the user according to the record changes.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
56
Subscribing to Record Changes
Test Subscriptions
Test Subscriptions
You can initially test subscriptions by running your app through Xcode and using CloudKit Dashboard to create,
modify, or delete records, as described in Add, Modify, and Delete Records (page 30). Then fully test subscriptions
by running your app on multiple devices. Use one device to make changes and another device to receive the
subscription notifications. You use multiple devices because a notification isn’t sent to the same device that
originated the notification.
For iOS, use an iOS device (not iOS Simulator) to test subscription notifications. Your app successfully registers
for push notifications if a dialog that asks the user’s permission for your app to receive notifications.
Recap
In this chapter you learned how to:
●
Subscribe to record changes by using a predicate
●
Handle subscription notifications
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
57
Testing Your CloudKit App
Give your CloudKit app a real-world test with multiple simultaneous users by running it on multiple devices
using different iCloud accounts. Both iOS and Mac apps can be configured to launch outside Xcode on
designated test devices. This is the recommended way to initially test your CloudKit app in the development
or production environment. Later upload your app to iTunes Connect to test your app using the production
environment. Using iTunes Connect, invite internal testers (your team’s iTunes Connect users) or invite external
testers (users specifying only their email addresses) to test your app. Testers download your app using the
TestFlight app.
To learn about distributing your app using TestFlight, read Beta Testing Your iOS App in App Distribution Guide .
Distribute Your iOS App Using Ad Hoc Provisioning
Ad hoc provisioning allows you to run your app on test iOS devices without needed Xcode. Before exporting
your app using an ad hoc provisioning profile, register all the devices you want to use for testing with Member
Center. Ad hoc distribution uses the same pool of devices that you register for development, so you are limited
to 100 per year. To register multiple test devices, read Registering Devices Using Member Center.
When you export your app for ad hoc testing, you choose the development or the production environment.
If you have not deployed your schema to production, as described in Deploy the Development Schema to
Production (page 62), choose the development environment.
To archive and export your app for ad hoc testing
1.
Choose an iOS device from the Scheme toolbar menu and click Run.
You can’t create an archive of a binary that is built for iOS Simulator.
2.
Choose Product > Archive.
The Archives organizer appears and displays the new archive.
3.
In the Archives organizer, select the archive and click Export.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
58
Testing Your CloudKit App
Distribute Your iOS App Using Ad Hoc Provisioning
4.
Select “Save for Ad Hoc Deployment,” and click Next.
5.
In the dialog that appears, choose a team from the pop-up menu and click Choose.
If necessary, Xcode creates a distribution certificate and an ad hoc provisioning profile for you.
6.
7.
In the next dialog, choose a container environment from the pop-up menu and click Next.
●
Choose Production to access the data in the production environment.
●
Choose Development to access the data in the development environment.
In the dialog that appears, review the app, its entitlements, and its provisioning profile, and click Export.
The name of the ad hoc provisioning profile begins with the text XC Ad Hoc:.
8.
Enter a filename and location for the iOS App file, and click Export.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
59
Testing Your CloudKit App
Distribute Your Mac App Using the Team Provisioning Profile
The file has an .ipa extension.
Later, send the iOS App file to testers. Instruct them to install the app on their iOS devices using iTunes, as
described in Installing Your App on Test Devices.
Distribute Your Mac App Using the Team Provisioning Profile
Register all the devices you want to use for testing with Member Center before exporting your app using
Xcode. To add multiple test devices to the team provisioning profile, read Registering Devices Using Member
Center. After you add devices, regenerate the team provisioning profile by refreshing profiles in Xcode, described
in Refreshing Provisioning Profiles in Xcode.
To export a code signed app using the team provisioning profile
1.
Choose a target from the Scheme toolbar menu, and click Run.
2.
Choose Product > Archive.
The Archives organizer appears and displays the new archive.
3.
In the Archives organizer, select the archive and click Export.
4.
Select “Export as a Mac Application.”
Xcode embeds the team provisioning profile in the bundle and code signs the app with your development
certificate.
Later, distribute the app to testers and run on the designated devices. The app will launch only on devices
specified in the team provisioning profile.
If you can’t launch the app on a designated device because it’s from an unidentified developer, bypass the
security settings in OS X to launch the app.
To open an app from an unidentified developer
1.
In Finder, Control-click the app icon.
2.
Click Open.
3.
In the Gatekeeper dialog that appears, click Open.
Recap
In this chapter you learned:
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
60
Testing Your CloudKit App
Recap
●
How to use the different methods to distribute your CloudKit app for testing
●
How to restrict your app to run on designated devices
●
For iOS apps, how to select the development or production container for testing
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
61
Deploying the Schema
After you finalize your schema and test your app in the development environment, you are ready to deploy
the schema to production. Deployment promotes the schema to the production environment, but it doesn’t
copy the records in the development environment to the production environment. Therefore, after deployment,
populate the production environment with records as needed. Then test your app in the production
environment. You can continue making changes to the schema in the development environment, but you are
limited to creating record types and adding fields. The next time you deploy the development schema, the
changes are merged with the production schema.
You must have privileges to edit the production environment to perform the tasks in this chapter. If you are
an individual, you are the team admin and have these privileges. Otherwise, ask your team admin to perform
these steps for you, or to grant you the Edit Production privilege, as described in Assign Roles to Other Team
Members (page 67).
When you are ready to submit your app to the store, read Submitting Your App to the Store in App Distribution
Guide .
Deploy the Development Schema to Production
The first time you deploy your app, CloudKit copies the container schema to the production environment. This
includes the record types, security roles, and subscription types, but not the records that you created in the
development environment. Once you deploy your schema to the production environment, you can’t delete
record types and fields that were deployed in the development environment.
Warning: To view records in production, enable the ID metadata index for the associated record types
before following these steps, described in Enable Metadata ID Indexes (page 24). You can’t change
the metadata indexes in the production environment.
To deploy a schema to production
1.
In CloudKit Dashboard, click Deployment in the left column.
2.
Click “Deploy to Production.”
3.
If an indexing dialog appears, click Optimize Indexes or Deploy Unused.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
62
Deploying the Schema
Deploy the Development Schema to Production
CloudKit tracks the index usage in the development, and shows you the estimated cost and size of each
index.
4.
●
To view the details of the unused indexes, click Unused Index Details.
●
To remove the unused indexes before deploying the schema, click Optimize Indexes.
●
To keep the indexes, click Deploy Unused.
●
To analyze the index usage before continuing, click Cancel and read Disable Unused Indexes (page
65).
In the dialog that appears, read the message and click Optimize & Deploy or Deploy Unused Indexes (the
button title depends on the option you choose in the previous dialog).
Verify Your Steps
Verify that the schema was copied to the production environment.
To view the production schema and data
1.
In the lower-left corner, click the Development button.
2.
In the dialog that appears, click Production.
The interface changes from the development to production environment.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
63
Deploying the Schema
Deploy the Development Schema to Production
3.
Click Record Types and select the record type you want to view.
4.
Click Default Zone to view public records.
To go back to the development environment, in the lower-left corner, click the Production button and click
Development.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
64
Deploying the Schema
Promote the Development Schema Changes to Production
Promote the Development Schema Changes to Production
The next time you deploy your schema to production, you can add only record types and fields to the production
environment. You can’t delete parts of the schema that are in production. CloudKit Dashboard merges the
new record types and fields with the production schema. You have the opportunity to review schema changes
before deploying the schema.
To promote the development schema to production
1.
In the development environment, click Deployment in the left column and review the changes you made
to the schema.
CloudKit Dashboard displays the changes to record types, subscription types, and security roles.
2.
Click “Deploy to Production.”
3.
If an indexing dialog appears, click either Optimize Indexes or Deploy Unused.
CloudKit tracks the index usage in the development. To see the estimated cost and size of each unused,
click Unused Index Details.
4.
In the dialog that appears, read the message and click Optimize & Deploy or Deploy Unused Indexes .
Disable Unused Indexes
Indexes improve the speed of fetching records from the database. CloudKit Dashboard creates indexes for
each field in a record type. Depending on the field type, CloudKit will create a sort, query, and search index.
This allows you to create queries using any field combination. In production, it’s wasteful to maintain and store
indexes for fields that you don’t use in database operations. You can save disk space, in both the public and
private databases, by disabling unused indexes.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
65
Deploying the Schema
Disable Unused Indexes
CloudKit tracks the index usage in both the development and production environments. Before you deploy
or promote the development schema, test your app thoroughly to create index metrics that represent real
world usage. Tune your database by disabling indexes for fields that you don’t use in sort, query, and search
operations. CloudKit Dashboard also estimates the cost of indexes derived from usage metrics.
You can disable unused indexes in the development and production environment.
To disable or enable an index for a field
1.
In the left column, click Record Types.
2.
In the second column, select a record type.
The field names and types appear in the detail area on the right. The Index column contains checkboxes
and the Cost column displays the estimated cost of the index.
3.
In the Index column, unselect a box to disable a type of index and select a box to enable a type of index.
●
If you don’t use the field in sort descriptors (set using the sortDescriptors method in CKQuery)
or sort records by the field in CloudKit Dashboard (described in Sort Records (page 32)), unselect the
Sort box.
●
If you don’t use the field in queries (CKQuery or CKQueryOperation objects) executed by your app,
unselect the Query box.
●
If you don’t search for records using the field (described in Search Records (page 31)), unselect the
Search box.
If you deploy the schema to production, as described in Deploy the Development Schema to Production (page
62), a dialog appears allowing you to disable unused indexes before deployment.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
66
Deploying the Schema
Assign Roles to Other Team Members
Assign Roles to Other Team Members
For company accounts, you can delegate some of the responsibilities of deploying your CloudKit app by
changing team member privileges, shown below.
Privilege
Description
Manage Team
Can change the privileges of other team members, except the team agent. The
team agent always has all privileges.
Edit Development
Edit Production
●
Can edit the development schema by using CloudKit Dashboard.
●
Can view records in development.
●
Can deploy the development schema to production.
●
Can view the production schema.
●
Can view and edit records in production.
You set the team member privileges separately for each container. The privileges don’t apply to all containers
belonging to a team.
To grant privileges to team members
1.
In CloudKit Dashboard, click Team in the left column.
2.
In the row of the team member and Privileges column, select the privileges you want to grant to the team
member.
If a privilege can’t be changed or you don’t have permission to change it, the checkbox is disabled.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
67
Deploying the Schema
Recap
Recap
In this chapter you learned how to deploy your development schema to the production environment and how
to keep it up to date as you continue developing your app.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
68
Document Revision History
This table describes the changes to CloudKit Quick Start .
Date
Notes
2015-06-27
Updated screenshots per the latest CloudKit Dashboard and applied other
minor edits throughout.
2015-04-08
Added "Adding Reference Attributes" chapter and revised "Deploying the
Schema" per CloudKit Dashboard indexing features.
2014-10-31
New document that introduces app development for CloudKit.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
69
Glossary
Apple Push Notification service (APNs) Apple
service for propagating information to iOS and OS
X devices.
public database A database for storing records
owned by the app that are shared between users.
An iCloud account is not required to read records
but is required to write records.
CloudKit An app service that stores structured
application and user data in iCloud.
push notifications A notification from a provider
to a device transported by APNs.
container A data store containing multiple database
used by one or more apps. The default container ID
matches the app’s bundle ID.
record An instance of a record type that can be
created, read, and written to a database.
database The portion of a container used to store
records. There’s one public database for the app and
multiple private databases—one private database
for each user.
record identifier An identifier for the location of a
record in a database. Contains a record name and
zone.
record name A unique identifier for a record within
a given zone. The record name is supplied by the
app and can be used as a foreign key in another data
source.
development environment Databases used to
develop your app and evolve the schema that is not
accessible by apps sold on the App Store or Mac App
Store.
record type A template for a set of records that
have common fields.
field A property of a record type that can be set
using a key-value pair.
record zone A partition of a database to store
records. Each database has a default zone and allows
additional custom zones.
just-in-time schema Development environment
feature that allows an app to create a schema by
saving records.
relationship A record type field that associates one
record to another.
predicate An object that defines logical conditions
for searching for objects conforming to key-value
coding.
role Permissions for a group of users to create, read,
and write records in the public database. The
possible roles are world, authenticated, and creator.
private database A database for storing records
owned by the current user that are not readable by
the app unless the user enters their iCloud
credentials on the device.
schema A collection of metadata that describes the
organization of records, fields, and relationships in
a database. In CloudKit, the schema includes record
types, security roles, and subscription types.
production environment Databases accessed by
apps sold on the App Store or Mac App Store.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
70
Glossary
subscription A persistent query on the server that
triggers notifications when records change.
to-many relationship An association between a
single record and one or more other records.
to-one relationship An association between a single
record and another single record.
2015-06-27 | Copyright © 2015 Apple Inc. All Rights Reserved. Apple Confidential Information.
71
Apple Inc.
Copyright © 2015 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrieval system, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer or device for personal use only and to
print copies of documentation for personal use
provided that the documentation contains
Apple’s copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-branded products.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, Finder, iTunes, Mac, OS X,
Sand, and Xcode are trademarks of Apple Inc.,
registered in the U.S. and other countries.
iCloud is a service mark of Apple Inc., registered
in the U.S. and other countries.
App Store and Mac App Store are service marks
of Apple Inc.
IOS is a trademark or registered trademark of
Cisco in the U.S. and other countries and is used
under license.
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED
“AS IS,” AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT, ERROR OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
Some jurisdictions do not allow the exclusion of
implied warranties or liability, so the above exclusion
may not apply to you.