Storing Key-Value Data in iCloud with Swift

Kristen

Hi, I’m Kristen––an iOS development newbie and Nice Mohawk’s summer intern. Most recently, Ben assigned me the task of building a simple example app that uses iCloud to store key-value data.

As one would expect, I immediately looked for a tutorial on the subject. I was disappointed, however, to come up short: all of the tutorials I found were written in Objective-C and I––the newbie who only knows Swift––could only half understand what was going on.

Thankfully, I did eventually figure out how to do all of this in Swift. It wasn’t too bad, either.

I decided to build an app with a text field and button, so that a user can type a short message and save it to iCloud. I began by setting up iCloud entitlements (see steps 1 & 2).

I then opened my ViewController.swift file and declared and initialized an NSUbiquitousKeyValueStore object:

var iCloudKeyStore: NSUbiquitousKeyValueStore? = NSUbiquitousKeyValueStore()

The NSUbiquitousKeyValueStore class allows you to save values of various types––NSNumber, NSString, NSDictionary, etc.––and associate them with a key. To save the user’s message for my app, I created an outlet for my text field and a function to call the setString:forKey and synchronize methods. setString:forKey: pairs the text field’s contents with a key, while synchronize saves the message to iCloud.

let iCloudTextKey = “iCloudText”
@IBOutlet weak var textField: UITextField!  

…

func saveToiCloud() {
    iCloudKeyStore?.setString(textField.text, forKey: iCloudTextKey)
    iCloudKeyStore?.synchronize()
}

I later realized that I should display the last message the user saved upon launching the app. To do this, I made a function that uses optional chaining and the stringForKey: method to check for and display a previously saved message.

func iCloudSetUp() {
    if let savedString = iCloudKeyStore?.stringForKey(iCloudTextKey) {
        textField.text = savedString
    }
}

Within the same function, I also registered for the NSUbiquitousKeyValueStoreDidChangeExternallyNotification notification so that my app could handle any changes made to the text field by other instances of the app while running.

✍ Ben: Sorry if you’re reading this on a phone screen. Some bits were overlooked in Cocoa’s conversion to Swift and haven’t transitioned as completely as others. Notification constant names are one where you can tell they didn’t get any love from Swift’s move toward more concise descriptors.

Using the addObserver method to do this also requires an additional function to take some sort of action. In my case, I made this function update the message in the text field.

func iCloudSetUp() {
    …
    NSNotificationCenter.defaultCenter().addObserver(self, 
        selector: “ubiquitousKeyValueStoreDidChangeExternally:", 
        name:  NSUbiquitousKeyValueStoreDidChangeExternallyNotification, 
        object: iCloudKeyStore)
}

func ubiquitousKeyValueStoreDidChangeExternally() {
    textField.text = iCloudKeyStore?.stringForKey(iCloudTextKey)
}

Here’s the finished project repository on GitHub. Note that the program is slightly more complicated, as I decided to incorporate a switch that allows the user to save text locally using NSUserDefaults or to iCloud.

And that’s it! Not too bad, right?

✍ Kristen is pursuing a CS degree at Ohio University and recently finished her freshman year. This summer she’s working on learning mobile development with Swift and updating Nice Mohawk apps built with Swift, namely TypeSnippets.