One of the best parts of CloudKit is how great it is at handling not just our models, but also larger assets like images, audio, or video.
Assets are saved just like any other property. Here we'll attach an image captured from the user's camera to a new record. Then we'll upload it to CloudKit using a CKModifyRecordsOperation (covered in more detail in Bite #31). In our case we're only saving a single record, but we're using an operation anyway, so we can take advantage of its perRecordProgressBlock, and track the upload progress of our asset.
funcimagePickerController(picker:UIImagePickerController,didFinishPickingMediaWithInfoinfo:[String:AnyObject]){guardletmediaURL=info[UIImagePickerControllerMediaURL]as?NSURLelse{return}letspaceshipRecord=CKRecord(recordType:"Spaceship")spaceshipRecord["model"]="Tantive IV"spaceshipRecord["maxSpeed"]=950// in kmspaceshipRecord["image"]=CKAsset(fileURL:mediaURL)letoperation=CKModifyRecordsOperation(recordsToSave:[spaceshipRecord],recordIDsToDelete:nil)operation.perRecordProgressBlock={self.progressView.progress=$1}operation.completionBlock={self.progressView.hidden=true}progressView.hidden=falseCKContainer.defaultContainer().publicCloudDatabase.addOperation(operation)}
It's worth noting that CloudKit doesn't seem to report progress constantly as we might expect. It seems to report between 0-3 times depending on the size of the asset we're uploading.
After fetching a record containing an asset, we can grab the downloaded file from disk using the fileURL property of the CKAsset:
Diving deeper into CloudKit today we'll look at some more advanced ways of interacting with your app's data using operations. CloudKit's NSOperation-based API allows for things like batch saves/changes, ‘paging' through data and more.
CKQueryOperation‘squeryCompletionBlock provides an optional CKQueryCursor. You can store this and supply it to your next query to load the next logical 'page' of records.
Progress
One of the great things about CKModifyRecordsOperation and CKQueryOperation is their ability to report progress at a per-record level.
We continue our tour through CloudKit today with a look at CKDiscoveredUserInfo and it's associated functions. CKDiscoveredUserInfo actually pop up in two different use cases: Grabbing the user's first and last name as well as letting them discover their friends who are also using your app. Let's get started, first we request permission:
Then we fetch the current user's CKRecord, and fetch their name:
container.fetchUserRecordIDWithCompletionHandler{(recordID,error)inguarderror==nilelse{return}guardletrecordID=recordIDelse{return}container.discoverUserInfoWithUserRecordID(recordID){(info,fetchError)in// use info.firstName and info.lastName however you need}}
All that's left is to let the user discover their friends:
container.discoverAllContactUserInfosWithCompletionHandler{(users,error)inguarderror==nilelse{return}guardletusers=usersas[CKDiscoveredUserInfo]else{return}foruserinusers{// use user.userRecordID to make// whatever connections you need}}
CloudKit lives on the client. You write Swift or Objective-C code to interact with Apple's iCloud servers to save and retrieve data. But what if your app wants to support push notifications? Don’t worry CloudKit has you covered. Use CKSubscription to tell CloudKit you'd like to know when records matching a predicate are created, updated, or deleted. CloudKit will deliver a special push notification to your app denoting the change, which you can customize for your needs.
Let's take a look at setting it up: (don't forget to setup and register for push notifications!)
letpublicDB=CKContainer.defaultContainer().publicCloudDatabaseletsubscription=CKSubscription(recordType:"Spaceships",predicate:NSPredicate(format:"TRUEPREDICATE"),options:.FiresOnRecordCreation)letinfo=CKNotificationInfo()info.alertBody="New Spaceship Entered the Fleet!"info.shouldBadge=truesubscription.notificationInfo=infopublicDB.saveSubscription(subscription){record,errorin}
Then when you receive the push notification use it's userInfo to create a CKNotification object and grab the ID of the new record:
letnotification:CKNotification=CKNotification(fromRemoteNotificationDictionary:userInfo)ifnotification.notificationType==CKNotificationType.Query{letqueryNotif=notificationas!CKQueryNotification// do something interesting with queryNotif.recordID}
CloudKit is Apple's API for storing and retrieving data from iCloud. With the recent introduction of the CloudKit Web Services API as well as CloudKit JS, CloudKit is now a very attracive option for the backend of your next app.
Let's take a look at the very basics of using CloudKit to create, retrieve, update and delete records:
Creating a Record
letpublicDB=CKContainer.defaultContainer().publicCloudDatabaseletspaceshipRecord=CKRecord(recordType:"Spaceship")spaceshipRecord["model"]="T-16"spaceshipRecord["maxSpeed"]=1200// in kmpublicDB.saveRecord(spaceshipRecord){(record,error)in}