In this lesson you learn how to save an item (with an image) in the default zone of the CloudKit’s public database. Here is a use case scenario of that task:
Code presented on this page assume you are using Xcode 6.4 and Swift version 1.2. So if you are using a newer version of Swift, it may produce errors. Fix them by using Xcode’s Fix-it tool. I assume you are a registered member of Apple’s iOS Developer Program, and you have a real iPhone/iPad device to test the CloudKit code presented here. |
Step 1: Add a record type in the CloudKitGuide container
To add an item record type in the CloudKit container load the CloudKit Dashboard in your browser (https://icloud.developer.apple.com/dashboard/). If necessary, sign into the Apple Developer portal. Next, select the CloudKitGuide container from the Container menu.
Next, select “Record Types” in the first panel. At the top of the third panel, click the Add New Record button (+) and enter Item in the record type field. The CloudKit Dashboard should look like this now:
Add these field names and field types for the Item record type.
Click the Metadata Indexes arrow. Configure the pop up menu so it look like the one shown in Figure 4, then click the Save button.
Now, there are three “Record Types” in the CloudKit database: Friends, Item, and Users.
Step 2: Update the Main View Controller scene and its class file
In order for the user to add details of an item in the view’s controls, configure the Main View Controller scene and its class file to look like this:
Now, when you run the app in the iPhone 6 Simulator, the mainView should look like this:
There are few things I want to point out about the MainViewController class file’s code.
- You conformed the class to three delegate protocols
- You assigned the CloudKit’s public database to a constant called db
- You entered code in three functions to dismiss the keyboard
The Image Selection Code
With that said, you have to enter code in the MainViewController.swift file to make the Choose Image button work. Start by adding entering code shown below in the Choose Image button’s function.
@IBAction func chooseImage(sender: UIButton) { itemName.resignFirstResponder() let imagePicker = UIImagePickerController() imagePicker.delegate = self imagePicker.allowsEditing = false imagePicker.sourceType = .PhotoLibrary imagePicker.modalPresentationStyle = .Popover imagePicker.popoverPresentationController?.sourceView = sender presentViewController(imagePicker, animated: true, completion: nil) }
Above code present an image picker view on the sim’s screen. So the user can select a photo from the sim’s Photo Library.
When the user finish picking an image from the sim’s Photo Library, the app should dump it in the imageView control. To perform this task, implement this delegate function of the UIImagePickerController class in the MainViewController.swift file.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) { var selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage imageView.image = selectedImage dismissViewControllerAnimated(true, completion: nil) }
Now, before you run the app on the iPhone 6 Simulator or on your real device, grab some photos off the web and add them in the simulator’s Photo Library or your device’s Photo Library. Another option is to click the link below to download photos shown in Figure A below. Figure B shows how to add them in the iPhone 6 Simulator’s Photo Library.
sample-photos |
Ok, I assume you’ve added above photos in the iPhone 6 Simulator; so run the app in the simulator. When the mainView appear on the sim’s screen do the following:
- Click the “Choose Image” button.
- Click the alert view’s OK button.
- Select an image from the sim’s Photo Library.
- The image picker view will disappear and the image you selected will appear in the main view’s imageView.
We’ve implement code in the MainViewController class file to enable the user to select a photo from the Sim’s Photo Library and dump it in the image view. Now, you have to add code in the class file to save the item details (item name and image) in the CloudKit’s public database. This will happen when you click the main view’s Save button. So locate its function in the MainViewController.swift file and add this code in it.
@IBAction func save() { // Dismiss the keyboard itemName.resignFirstResponder() if thisApp.userSignedIn == false { // The app user's iCloud account is not authenticated textView.text = "iCloud is not available.\n\nPlease do the following:\n\n" + "1. Sign into your iCloud account\n" + "2. Turn on iCloud Drive via the Settings app\n" + "3. Relaunch the app" // Don't execute code below this if block return } if itemName.text.isEmpty { textView.text = "Can't save, the item name is required." return } var photoUrl: NSURL! let item = DatabaseHeleper() item.itemName = itemName.text item.itemPhoto = imageView.image! textView.text = "Saving item..." // Check to see if the item already exists in the CloudKit's public database let predicate = NSPredicate(format: "itemName = %@", itemName.text) let query = CKQuery(recordType: "Item", predicate: predicate) db.performQuery(query, inZoneWithID: nil, completionHandler: ({results, error in if (error != nil) { NSOperationQueue.mainQueue().addOperationWithBlock { self.textView.text = "Search query error: \(error.localizedDescription)" } } else { if results.count > 0 { // The item does exists in the CloudKit public database // Update the UI control on the main thread NSOperationQueue.mainQueue().addOperationWithBlock { self.textView.text = "That item already exists in the database." } } else { // The item doesn't exist in the CloudKit public database // Insert the photo in the app's Documents directory photoUrl = item.saveImageInDocumentsDir(self.imageView.image!) // Create an id for the CKRecord let itemId = item.randomStringWithLength(3) // Create an asset object and initialized it let photoAsset = CKAsset(fileURL: photoUrl!) // Create a CKRecord object let itemRecord = CKRecord(recordType: "Item") // Set the CKRecord object's properties itemRecord.setObject(itemId, forKey: "itemId") itemRecord.setObject(self.itemName.text, forKey: "itemName") itemRecord.setObject(photoAsset, forKey: "itemImage") // Save the CKRecord object in the CloudKit public database self.db.saveRecord(itemRecord, completionHandler: {returnedRecord, error in if error != nil { // Update the UI control on the main thread NSOperationQueue.mainQueue().addOperationWithBlock { self.textView.text = "Save item error: \(error.localizedDescription)" } } else { // Update the UI on the main thread NSOperationQueue.mainQueue().addOperationWithBlock { self.textView.text = "Item saved." } } }) } } })) }
Yes, I Know that’s a lot of code for such a simple task. However, the comments should help demystify the code’s logic. Go ahead and run the app in the iPhone 6 Simulator. Enter a name in the textField and use the Choose Image button to select a photo from the sim’s Photo Library. When you are done, click the save button and you should see output shown in the Figure A below. If you click the Save button without entering a different item name in the textField; the app will not save the item name and image in the public database. It will simply display the message shown in Figure B. Figure C is the CloudKit Dashboard view of the item you entered in the CloudKit’s public database.
That’s pretty much it. You entered code in the MainViewController.swift file to save an item (with an image) in the default zone of the CloudKit’s public database. Comments are welcomed! 🙂