Core Data with CloudKit: Exploring the CloudKit Dashboard
In this article, we will explore the CloudKit Dashboard
.
Don’t miss out on the latest updates and excellent articles about Swift, SwiftUI, Core Data, and SwiftData. Subscribe to fatbobman’s Swift Weekly and receive weekly insights and valuable content directly to your inbox.
In light of the fact that my blog, Fatbobman’s Blog, now offers all articles in English, starting from April 1, 2024, I will no longer continue updating articles on Medium. You are cordially invited to visit my blog for more content.
Introduction to the Dashboard
To use the CloudKit Dashboard
, developers need to have an Apple Developer Program account and can access it at https://icloud.developer.apple.com.
In the past two years, Apple has made significant adjustments to the layout of the CloudKit Dashboard
. The screenshot above shows what it looked like in mid-2021.
The original article was written in Chinese and published on my blog 肘子的Swift记事本.
Part 2: Syncing Local Database to iCloud Private Database
Part3: Exploring the CloudKit Dashboard
Part5: Synchronizing Public Database
Part6: Sharing Data in the iCloud
The Dashboard consists of three main sections:
Database (CloudKit Database
)
A web client for the database. It covers features such as managing schemas, records, zones, user permissions, and container environments.
Telemetry (Telemetry
)
Uses intuitive visual effects to gain insight into server-side performance of the application, as well as the utilization of cross-database and push events.
Logs (Logs
)
CloudKit servers generate real-time and historical logs, recording and displaying interactions between the application and server.
In most scenarios that use
Core Data with CloudKit
, we only need to use a few features of the Dashboard (environment deployment). However, by utilizing theCloudKit Dashboard
, we can gain a clearer understanding of some of the mechanisms behind the operation ofCore Data
data synchronization.
Database (CloudKit Database
)
In The Basics, we have briefly introduced basic objects such as CKContainer
, CKDatabase
, CKZone
, CKSubscription
, and CKRecord
. In this article, we will also introduce some other objects and features of CloudKit
.
Environment
CloudKit
provides separate development and production environments for your application's network data.
Development Environment
When your project is still in development, all data generated through CloudKit
is only saved in the development environment, and only members of the development team can access the data in this environment. In the development environment, you can adjust the Schema
structure and delete or modify the properties of Record Types
at any time. Even if these operations may cause data conflicts between different versions, it is not a problem as the development environment can be reset anytime. This is very similar to the state of an application using Core Data
before it goes live; even if data cannot be migrated correctly, just deleting and reinstalling the app will suffice. Through the development environment, developers can thoroughly test the application before providing CloudKit
services to users.
Production Environment
When the application is developed and ready to be submitted to the App Store, the structure of the development environment needs to be deployed to the production environment (Deploy Schema Changes
). Once the Schema
is deployed to the production environment, developers cannot modify the Schema
as freely as they can in the development environment. All modifications must be made in a forward-compatible way.
The reason is straightforward. Once the application goes live, we cannot control the update frequency of the client, which means that the client may have any structure version. In order to allow low-version clients to access the data, any changes to the data model need to be backward-compatible.
Applications sold on the App Store can only access the production environment.
Even if the developer’s developer account is the same as their personal iCloud account, the development and production environments are two separate sandboxes, and data does not affect each other. When debugging the program using Xcode
, the application can only access the development environment, while the application downloaded through Testflight
or the App Store can only access the production environment.
In the development environment, click on Deploy Schema Changes
to deploy the Schema
of the development environment to the production environment.
During deployment, modifications made in the development environment since the last deployment will be displayed.
Even if the Schema
has been deployed to the production environment, we can still make changes in the development environment and deploy them to the production environment. If the model does not meet compatibility requirements, the CloudKit
dashboard will prohibit your deployment.
Whether the Schema
has been deployed to the production environment is shown below the container name. The above picture shows the undeployed state, while the following picture shows the deployed state.
Before performing any operation, be sure to confirm that you are in the correct environment setting.
Given the deployment rules of
CloudKit
environments, when designing aCore Data
data model in a project that usesCore Data with CloudKit
, you must be particularly careful! My personal principle is to add and subtract, and avoid changing as much as possible. I will discuss in detail how to migrate versions ofCore Data with CloudKit
data models in the next article.
Security Roles
Security roles are only applicable to public databases.
CloudKit
uses role-based access control (RBAC
) to manage permissions and control access to data in public databases (private databases are exclusive to the application's users). With CloudKit
, you can set permission levels for a role and then assign that role to a given record type.
Permissions include read, write, and create. Read permission only allows reading records, write permission allows reading and writing records, and create permission allows reading, writing, and creating new records.
CloudKit
includes 3 preset roles, which are World (_world
), Authenticated (_icloud
), and Creator (_creator
). World represents anyone, whether or not they are an iCloud user. Authenticated applies to any verified iCloud user. Creator is the creator of the record.
By default, anyone can read data, only verified iCloud users can create new records, and record creators can update their own records.
We can create custom security roles, but we cannot create user records. The system will create a user record for the user when they first authenticate with the container. We can look up existing users and assign them to any custom roles.
Security roles are part of the data schema, and whenever a developer modifies security settings, they need to deploy it to the production environment for it to take effect. Security roles cannot be deleted after deployment.
For most
Core Data with CloudKit
applications, using the default configuration provided by the system is sufficient.
Indexes
CloudKit
indexes are divided into three types:
- Queryable
- Searchable
- Sortable
After creating a Record Type
through CloudKit
, we can create the required indexes for each field as needed (only NSString
supports searchable). Index type options are independent, so if you want a field to be both queryable and sortable, you need to create two indexes separately.
Only after creating a queryable
index for the recordName
of the Record Type
can you browse the data for that type in Records
.
Core Data with CloudKit
automatically creates the required indexes onCloudKit
for each attribute of theCore Data
data model (excludingrecordName
). We don't need to add any indexes unless we need to browse data on theCloudKit
dashboard.
Record Types
A Record Type
is a type identifier specified by developers for CKRecord
. You can create it directly in code or create and modify it in the CloudKit
dashboard.
In the basics section, we mentioned that an Entity
has more configuration information than a Record Type
. However, Record Type
has a feature that Entity
does not have - metadata.
CloudKit
has several pre-set metadata fields for each Record Type
(even if the developer has not created any other fields), and each data record (CKRecord
) will contain this information, most of which are automatically set by the system.
createdTimestamp
The time when CloudKit
first saved the record to the server.
createUserRecordName
The user record of _creator
, which is saved in Users
(created by the system). The system creates a user record for the user when they first authenticate with the container.
_etag
Version token. Each time CloudKit
saves a record, it updates it to a new value. Used to compare the version of network and local data.
modifiedTimestamp
The most recent time when CloudKit
updated the record.
modifiedUserRecordName
The user record of the user who last updated the data.
recordName
The unique ID of the record. Created when creating CKRcord
, usually set to a UUID
string.
For some special types of Record Type
, the system will also add some targeted metadata, such as role
,cloud.shared
, etc.
The main topic of this article is Core Data with CloudKit
, so let's take a look at how NSPersistentCloudKitContainer
converts the properties of Core Data
managed objects into Record Type
fields in CloudKit
.
The above figures show the
Record Type
corresponding to theItem
template project inCloudKit
in Syncing Local Database to iCloud Private Database.CloudKit
automatically creates a field for each property of the managed object entity, mapping the property name to a field with the keyCD_[attribute.name]
. The type of this field may also differ betweenCore Data
andCloudKit
. The name of theRecord Type
isCD_[entity]
. All operations are automatically performed by the system, and no intervention is required. In addition, aCD_entityName
field is generated for theEnitity
, which contains the class mapping name of theEntity
.
These strings with the prefix CD_
will appear repeatedly in the console during data synchronization, and understanding their composition is helpful for debugging the code.
After deploying the Record Type
to the production environment, fields cannot be deleted, and field names cannot be changed. Therefore, some operations in Core Data
are not allowed in `Core Data with CloudKit`.
Please do not rename the Entity
or Attribute
of the data model of an application that has already been deployed, even if you use Mapping Model or Renaming ID. If renaming is required during the development phase, you may need to delete the app, reinstall it, and reset the development environment of CloudKit
.
Even if you have deleted an Attribute
of an Entity
in Core Data
, the field will still exist in the Record Type
(and will not affect synchronization).
Zones
Each type of database has a default Zone
, and only private databases can customize their Zone
.
For data in a private database, you can specify a Zone
for the data when creating a CKRecord
.
let zone = CKRecordZone(zoneName: "myZone")
let newStudent = CKRecord(recordType: "Student",
recordID: CKRecord.ID(recordName: UUID().uuidString,
zoneID: zone.zoneID))s
When NSPersistentCloudKitContainer
converts managed objects to CKRecord
, it sets the ZoneID
to com.apple.coredata.cloudkit.zone
by default. You must switch to the correct Zone
to view the data.
OWNER RECORD NAME
User record, corresponding to _creator
of the Zone
CHANGE TOKEN
Comparison token
ATOMIC
If set to true
, the entire operation fails when CloudKit fails to update one or more records in a Zone
.
Records
Used for browsing, creating, deleting, modifying, and querying data records.
When browsing data, please pay attention to the following points:
- Select the correct environment (the data in the development environment and the production environment are completely different).
- Select the correct
Database
andZone
. - Confirm that the metadata
recordName
of theRecord Type
you want to browse has already added aqueryable
index. - If you need to sort or filter fields, create an index for the field.
- Indexes only take effect in the production environment after deployment.
Modifying the mirrored data of
Core Data
in theCloudKit
dashboard will immediately trigger a remote notification and update on the client side. However, this approach is not recommended.
You can also get the CKRecord
corresponding to the Core Data
managed object:
func getLastUserID(_ object:Item?) -> CKRecord.ID? {
guard let item = object else {return nil}
guard let ckRecord = PersistenceController.shared.container.record(for: item.objectID) else {return nil}
guard let userID = ckRecord.lastModifiedUserRecordID else {
print("can't get userID")
return nil
}
return userID
}
The above code will obtain the last modified user for the CKRecord
corresponding to the managed object record.
Subscriptions
Browse the CKSubscription
s registered on the container.
CKSubscription
s are created through code and can only be viewed or deleted on the dashboard.
For example, the following code creates a CKQuerySubscription
:
let predicate = NSPredicate(format: "name = 'bob'")
let subscription = CKQuerySubscription(recordType: "Student",
predicate: predicate,
options: [.firesOnRecordCreation])
let info = CKSubscription.NotificationInfo()
info.alertLocalizationKey = "create a new bob"
info.soundName = "NewAlert.aiff"
info.shouldBadge = true
info.alertBody = "hello world"
subscription.notificationInfo = info
publicDB.save(subscription) { subscription, error in
if let error = error {
print("error:\(error)")
}
guard let subscription = subscription else { return }
print("save subscription successes:\(subscription)")
}
NSPersistentCloudKitContainer
registers aCKDatabaseSubscription
for the privately mirrored database ofCore Data
. When thecom.apple.coredata.cloudkit.zone
data is updated, a remote notification will be pushed.
Tokens&Keys
Set the API token for the container.
In addition to operating data through code and the CloudKit
dashboard, Apple also provides means to access iCloud data from the internet or other platforms. After obtaining the token, developers can interact with data using CloudKit JS or CloudKit Web Services.
Some developers have used these services to develop third-party libraries that can access iCloud data on other platforms, such as DroidNubeKit (accessing CloudKit
on Android).
For network mirrored data in
Core Data
, it is not recommended to attempt this unless your data model is simple enough.CloudKit Web Services
are more suitable for data records created directly throughCloudkit
.
Sharing Fallbackd
Sharing Fallbackd provides data recording and sharing callback support for operating systems below iOS 10 and macOS Sierra.
Telemetry
By viewing Telemetry metrics, you can visualize performance while developing or updating your application. This includes the number of requests, errors, pushes, server latency, and average request size, among others. By setting the range, only data relevant to you is displayed, helping you better understand traffic configuration and usage trends for your application.
Logs
In the historical logs, you can view information such as time, client platform version, user (anonymous), event, organization, and details.
While providing detailed information, CloudKit strives to maintain user data privacy. The logs display server events recorded for each user, but do not expose any personal identity information. Only anonymous, container-specific CloudKit users are displayed.
App Store Connect’s analytics information only comes from users who have agreed to share diagnostic and usage information with app developers, while CloudKit log information comes from all users who have used CloudKit services in your application. Using both together can yield better results.
Conclusion
For most scenarios using Core Data with CloudKit, developers generally do not need to use the CloudKit dashboard. However, occasionally studying the data on the dashboard can also be a good source of fun.
In the next article, we will discuss some situations that developers often encounter when developing Core Data with CloudKit projects, such as debugging, testing, and data migration.
If you found this article helpful or enjoyed reading it, consider making a donation to support my writing. Your contribution will help me continue creating valuable content for you.
Donate via Patreon, Buy Me aCoffee or PayPal.
Want to Connect?
@fatbobman on Twitter.