iCloud is Hard

I’ve spent a lot of time over the last few months talking to people about CoreData’s iCloud syncing features. One complaint I hear is that Apple should make the API easier to implement and handle problems automatically for the developer. CoreData’s persistent store iCloud syncing API has it’s faults, but I think developers underestimate how many issues are out of Apple’s control.

Online vs. Offline Data

One of the biggest reason enabling a persistent store isn’t just as easy as checking a box in Xcode is because you don’t necessarily want all your data syncing in the cloud. You may have multiple stores containing information that should stay off the cloud, and even multiple stores syncing over iCloud. This sort of complexity has to be handled at a code level by the developer.

Conflict Handling

Another problem that makes persistent stores difficult is handling record conflicts. Would it be possible for Apple to automatically handle conflicts?

Screen Shot 2013 02 21 at 8 43 03 PM

Assume the above records are new and were both created by devices that were offline, maybe an Wifi iPad and an iPod Touch. Both devices come back online, and the above records are sent to iCloud and synced across devices.

How is this conflict handled? Maybe these are entirely independent records and shouldn’t be merged, like a call history. Or possibly these records should be merged together.

But merging these records together raises a new set of questions. CoreData could assume that the merged record should contain the “home” and “work” fields of it’s ancestors. But what if the app considers those fields mutually exclusive, and only one can be filled in?

Or possibly, even though it’s a poor user experience, the user will need to be notified of the conflict and resolve it themselves.

Automatic conflict detection would make too many assumptions to be reliable. Apple’s choice of making the developer handle conflict detection and resolution is a sound one.

(APIs like Simperium promise to handle conflicts automatically, but according to the documentation the automatic conflict resolution seems to be limited to modifications of an existing record, which iCloud automatically handles as well.)

UI Updates

Cloud sync means records can change or be added independently of user interaction, which means code has to be written to deal with data changing independently. NSFetchedResultsController can deal with some of the pain by automatically updating table views when changes are made, but the interactions with iCloud updates can be flakey. I’ve burned a lot of time before on getting NSFetchedResultsController to play nice with iCloud.

Bindings from the Mac would be a great way to help solve this issue on the iPhone. If it was possible to just bind fields to CoreData, updates would get pushed to the UI automatically. Key value observers or other bindings frameworks are another tool developers can use to deal with this problem, but they still aren’t as clean or simple as bindings.

This could also be an issue that is easier to deal with in new applications. I think it can be frustrating dealing with this issue in existing applications, but if the application isn’t built to respond to changes coming from someplace other than the user, there isn’t much Apple can do to deal with this problem for the developer.

What’s Broken

If the user logs out of iCloud, it could break an application. The underlying stores are removed without the app being notified, which could lead to crashes and data loss. iOS 6 will now send a notification if the user logs out of iCloud, but no notification is sent if the user turns off document syncing. This is tricky to have automatic behavior around, especially on Mac where the user can log out of iCloud without your app even being suspended. One possible solution is Apple forcing a restart on iOS and a logout on OS X to force any applications that could be interacting with iCloud to close before the changes are made.

iCloud quotas can make testing difficult. If too many changes are pushed to iCloud too quickly, iCloud will begin to delay propagating those changes to clients. This means if you’re testing an application, it could take 15 minutes for a change to appear across devices, which can slow down debugging sync issues. iOS 6 increased the quota, but it can still be hit during heavy testing. It’s great that Apple is making developers think about not pushing too much data to iCloud at once, but it would be great if developers were able to temporarily disable this quota.

I’ve heard reports of data simply getting lost and never arriving on different devices, but I’ve never seen this behavior.

Conclusion

iCloud isn’t perfect, but developers should have realistic expectations going in to implementing cloud sync. There are a lot of situations that can only be handled by the developer. Apple should make reasonable changes to make the technology more stable and more reliable, but developers should also have reasonable expectations for what’s involved in slinging records between mobile devices across the internet.

I also really would like to see iCloud CoreData syncing succeed. Competing services and platforms like Dropbox and Android only offer file level sync, which has it’s own data loss issues and use a lot more bandwidth. For mobile development, transaction based syncing really is the best way to go. If Apple fixes the stability issues hopefully they can convince some developers to support the the technology again.