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 Cloud Kit 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, as they appear in CloudKit Dashboard, and their equivalent CloudKit framework 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 |
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).

In the code, the underlying object model consists of an Artwork
and Artist
class where Artwork
has a to-one relationship to Artist
.
In the schema, 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 Programmatically
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.
To create a record in code
Create a record ID specifying a unique record name.
let artworkRecordID = CKRecordID(recordName: "115")
CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"115"];
Create a record object.
let artworkRecord = CKRecord(recordType: "Artwork", recordID: artworkRecordID)
CKRecord *artworkRecord = [[CKRecord alloc] initWithRecordType:@"Artwork" recordID:artworkRecordID];
Set the record’s fields.
artworkRecord["title"] = "MacKerricher State Park" as NSString
artworkRecord["artist"] = "Mei Chen" as NSString
artworkRecord["address"] = "Fort Bragg, CA" as NSString
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
Get the database in your app’s default container.
To get the public database:
let myContainer = CKContainer.default()
let publicDatabase = myContainer.publicCloudDatabase
CKContainer *myContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [myContainer publicCloudDatabase];
To get the private database:
let myContainer = CKContainer.default()
let privateDatabase = myContainer.privateDatabase
CKContainer *myContainer = [CKContainer defaultContainer];
CKDatabase *privateDatabase = [myContainer privateCloudDatabase];
To get a custom container:
let myContainer = CKContainer(identifier: "iCloud.com.example.ajohnson.GalleryShared")
CKContainer *myContainer = [CKContainer containerWithIdentifier:@"iCloud.com.example.ajohnson.GalleryShared"];
To create a custom container shared by multiple apps, read Share Containers Between Apps.
Save the record.
publicDatabase.save(artworkRecord) {
(record, error) in
if let error = error {
// Insert error handling
return
}
// Insert successfully saved record code
}
[publicDatabase saveRecord:artworkRecord completionHandler:^(CKRecord *artworkRecord, NSError *error){
if (error) {
// Insert error handling
return
}
// Insert successfully saved record code
}];
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 development, when you run your app through Xcode on a simulator or a device, you need to enter iCloud credentials to read records in the public database. 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.
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
Choose Xcode > Open Developer Tool > iOS Simulator.
In iOS Simulator, choose Hardware > Home.
Launch the Settings app and click iCloud.
Enter an Apple ID and password.
Click Sign In.
Wait while iOS verifies the iCloud account.
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.
Alert the User to Enter iCloud Credentials
Improve the user’s experience by verifying that the user is signed in to their iCloud account before saving records. If the user is not signed in, present an alert instructing the user how to enter their iCloud credentials and enable iCloud Drive. Insert your code that saves records in the else
clause below.
[[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.
View Record Types by Using CloudKit Dashboard
Verify that the record types have the correct field names and types.
To view record types
Sign in to CloudKit Dashboard.
Choose the container used by your app from the list.
Select Data in either the Development or Production environment.
In the tab bar, click Record Types.
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.
Enable RecordName Indexes Before Viewing Records
All the metadata indexes for record types created using just-in-time schema are disabled by default. The recordName query index needs to be enabled to view the associated records in CloudKit Dashboard.
To enable the recordName query index
In the tab bar, click Indexes and select a record type.
Click Add Index and select the recordName field.
Click Save Record Type.
View Records Using CloudKit Dashboard
Verify that the records you saved have all the data.
To view records
In the tab bar of CloudKit Dashboard, click Records.
Define your query by adding a filter or sort criteria.
Click Query Records.
In the second column, select a recordName.
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
Copyright © 2017 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2017-09-19