iOS 8

iSource 2.5.2 and submitting bug fixes

iSource MLA and APA 2.5.2 will be available on the App Store next week and include a few fixes for issues that appeared with the release of iOS 8.1.

iOS 8.1 introduced an issue where the text entry sheet wouldn't display properly, effectively leaving you with a modal view you couldn't dismiss. It's fixed in this update.

I'd like to take a moment and re-affirm the importance of letting an app's developer know when you've run into a bug in their app. Apps, like children, can misbehave. I always want to hear from you if you've run into an issue so I can get it fixed as soon as possible. iSource, Bug Trackr, Academy Coins, and Screenshot++ all include a feedback form in the About page.

If you notice any issues in iSource 2.5.2, let me know!

PS, stay tuned for some big iSource news in the coming weeks. 

Psst, iSource 3 is coming in 2015!


Developing For CloudKit- Part 2

Read Part 1 in series on Developing for CloudKit

It's been a week since my first post on developing an iOS app that uses CloudKit as a syncing solution to work with Core Data. Creating a mediation layer between Core Data and CloudKit has been no walk in the part but it's simpler than it first seemed.

My app, for now, doesn't need to make changes to its data objects. I'm constricting myself to the creation and deletion of objects in CloudKit. That decision has taken a load off my plate as I, for the first time, tackle sync totally by myself.

I started with converting NSManagedObjects to CKRecords. After the upload is complete, I use the (NSString *)recordName from CKRecord's (CKRecordID *)recordID returned from the completion handler and save that back to the NSManagedObject. This allows me to keep a local reference matching an NSManagedObject to the corresponding CKRecord stored in CloudKit. For local objects that don't have a valid recordName, I'll get to that in a bit.

Next is delete, very similar, I first delete the matching CKRecord in CloudKit (if there is one) and then delete my local copy once the server deletion is finished. CloudKit has extremely useful block callback and I highly suggest you use them!

Run that on 2 devices, add an object on the first device and... nothing happens. What?

We'll have to create a CKSubscription that will send a Push Notification to other devices signed into the same iCloud account when a CKRecord was uploaded, deleted, or updated in CloudKit. I won't go into detail about APNS here but it's not entirely complicated. Each notification will (for the most part) give you a reference to the changed object in its payload. Use that to update the corresponding NSManagedObject.

Now we have an app that syncs out locally saved data but for a device to get changes, it has to be on, open to the app. An app that isn't running will never know about changes. Next we have to add a way for our app to query the server when launched. This is a little more difficult than the steps I've covered so far.

Checking for changes that occurred while offline or in airplane mode will be done in 3 stages.

The first, to backtrack a bit, we need to keep track of objects that were deleted while offline. and delete them before the next steps. If we forget this, any offline deletions will be re-added later and create a frustrating problem for the user.

Second, we check for any CKRecords in CloudKit that we don't have a matching copy of on our local device. Start by getting a list of all CKRecordIDs, compare that to all objects we have locally, and remove the matches. Now, you're left with a list of CKRecords to download.

After that, check for local objects with a valid recordName property. Local objects with a recordName that no longer exists on the server means that object has been deleted on another device. You can safely remove those objects.

Once that's complete, you've successfully updated your device with changes made on CloudKit's server, but that's only half the story. We finish by reversing that process and updating CloudKit with changes to out local objects that happen while offline. 

This process is a little faster than the last. Start by creating an array of local objects that have a nil recordName. These have either never been synced or the upload wasn't successful. Either way, they need to be uploaded, do that now.

After that, you're done. (I say that knowing I've probably forgotten a step and will feel pretty foolish when my inbox fills up. Email Marco.)

I hope this has helped you, writing it all out helped me realize I forgot a step in my code. Bonus points if you can figure out what step I added at the last minute.

Update: Screenshot++ is now available with the CloudKit sync engine. Give it a spin!

Academy Coins 1.4 available now!

Academy Coins has just been updated with support for iOS 8 including a new Today Widget!

  • The new Today Widget gives you an overview of your child's progress in the game without having to open the app (so they never have to know you're checking up on them). To enable, open Notification Center, scroll down and press the Edit button, then press the '+' next to Academy Coins.
  • The Dollars or Cents level has been rewritten and provides a big boost in performance and reliability.

I'm currently planning the next version of Academy Coins. What new currencies should be included in this new version? Let me know through the app!

Ambiguous App Store Guidelines

Panic's Transmit 1.1.1 is the latest app to fall victim to Apple's ambiguous App Store Guidelines. We have an exceptional app, made by talented and bright individuals, receiving a rejection because it violated a vague clause in the App Store Guidelines.

PCalc, another great calculator app, was recently rejected for adding calculation functionality into their iOS Today Widget even though Apple's Calculator app for OS X includes the same functionality.

Transmit, according to the App Store Review Team, was in violation because it sent data to other services that wasn't created in the app itself. Bah-humbug.

Transmit and PCalc aren't alone in trying to McGiver the increasingly vague guidelines, these are simply recent entries in a long list.

Apple seemed to be embracing developers at this year's WWDC, it seemed as though they were on our side. Looks like we jumped the gun. They have their own interests, of course, but it seemed we were in a new age of transparency.

iOS developers are now increasingly apprehensive to push the envelope on what's possible and that can only result in a poorer user experience.

Final note: as we steadily march forward to feature parity between iOS and OS X, why hinder the iOS platform? What division within Apple is reigning developers back?

The infighting within Apple is becoming clear and users and developers are taking the brunt end.

Developing with CloudKit - First Impressions

I've recently started work on a new app that uses iOS 8's new CloudKit framework. I'm using CloudKit as the storage backend and Core Data for the local cache. So far, I'm impressed. CloudKit is a much-welcome departure and improvement over iCloud's Core Data Sync.

Before CloudKit, we relied on iCloud's Core Data sync mechanism to transfer data between devices. From the start, it was unreliable at the best of times. There was a fair bit of magic going on behind the scenes and the lack of transparency from Apple made debugging impossible. With new OS versions came significant increases in reliability but it problems persisted.

CloudKit aims to remove that magic and be as transparent as possible. In return, CloudKit is a transportation layer, sans magic. In essence, it handles sending data to iCloud, storing that data, and notifying your app where there's new data to be downloaded. The rest is up to you.

And that's actually a pretty great thing. This new app I'm working on simply takes an image, some strings and dates, and send that as a packaged object to the cloud. Setting up the sync part was actually pretty simple and took less than a day. It worked reliably, even with the network conditioner set to a poor network connection.

Next was implementing local offline storage. This is the tricky part.

I want to have the data saved onto the device for offline use and because some of the data is large and I respect my customer's data bills. When the device returns to the network, any changes are propagated via CloudKit.

Sounds a lot like sync, what's the difference?

Instead of creating a Core Data stack and then trying to get sync to work, I'm developing for CloudKit first. I'm getting Core Data to work nicely with CloudKit instead of trying to force CloudKit to play nicely with Core Data. This seemingly small distinction makes a large impact. Core Data is a robust framework and, thanks to Magical Record, is exceptionally flexible. CloudKit, on the other hand, is straight-forward and lean. 

On one side, we have CloudKit, the other the highly flexible Core Data. Now we need something to communicate between the two, like a translator. Let's call this the Intermediary.

With the ClouKit approach, Apple has left the Intermediary up to developers. This Intermediary is what I was referring to by the 'magic' of iCloud Data Sync. What happens when you try to create an Intermediary that has to cover all possible data structures and scale well? Turns out, not well.

So what I need is a simple, generic Intermediary that fits, but is not limited to, the data schemas I'm using. Data created on the device (NSManagedObject *) is saved via Core Data, the Intermediary is notified of the changes and converts the data to a CloudKit record (CKRecord *), and the record is handed off to Apple's servers via CloudKit. Any data in iCloud that's not on the device is brought down in the opposite direction converting the CKRecord back into, or creating, an NSManagedObject.

Because of the object type conversion, I have to keep a reference to later know which NSManagedObject corresponds to which CKRecord. If a new record was downloaded and I didn't know which local object to match it to, I would end up with endless duplicates. So do I save a reference to the NSManagedObject in the corresponding CKRecord or save a reference of the record in the object? 

For now, I'll try keeping a reference to the CKRecordID because UIDs on NSManagedObject change with each device. At least, that's the way it seems. More on that next time. I have my work cut out for me.

As Steve said, "The truth is in the Cloud". CloudKit is a lesson in treating cloud data as a first class citizen. 

Update: Screenshot++ is now available on the App Store with the CloudKit sync engine. Give it a spin!

Marketing Resource for iOS Bundles


If you've recently put together an iOS App Bundle, like I have, you may be wondering where you can find the Marketing Resources.

For iOS apps, Apple provides us with guidelines and image resources for marketing purposes. This includes assets and user guidelines for the App Store Badge, psd files for currently supported iOS devices for dropping screenshots into, App Banners, and the like.

Head over to Apple's Developer Page for an explanation of iOS Bundles. Apparently though, that's it. 

How are developers supposed to advertise their Bundles?

I tried to create and then hack an App Banner (link) using the Bundle's Apple ID. The result was a blank frame. Using the Link Maker tool returned no results for my bundle.

Let's try creating something simple - an image of the bundle and an App Store link for my website.

Since the bundle icons seem to be generated though iTunes Connect, can I download a high-res version? I haven't yet found a way. Perhaps the App Store is laying out the individual icons rather than flattening them into a single bundle icon image. So far, I haven't been able to find any information. 

iTunes Connect does provide the App Store url for the bundle. So that's one step in the right direction.

It's odd Apple has so little guidance on the subject. I'm left with two conclusions. Either developers are not intended to specifically advertise their App Bundles on their website or it's an oversight on Apple's part. I'm getting the feeling the former is true.

If you've come across anything useful, let me know at w.dyson [at] me dot com.


Bug Trackr 2.0 Public Beta

Update: The beta period has ended and version 2.0 is on the App Store now. Thank you to everyone who participated, much appreciated!

I'm rounding out development on Bug Trackr 2.0 and thanks to Apple's new TestFlight service, I'm accepting 1000 helpful iOS 8 users to try out the new version.

Bug Trackr 2 adds a new Today Widget, Notes and Screenshots in each bug report, and support for iO8, iPhone 6, and iPhone 6 plus. 

If you'd like to sign up for the beta, head over to the Bug Trackr Home Page.

Please note the beta requires an iOS device running iOS 8 and later. Be sure to backup your device before installing the beta as you may have to re-install the app when the final version is released.

Thank you!

iSource APA and iSource MLA 2.5 available now!

iSource APA and iSource MLA 2.5 have just been released and the update brings support for iOS 8, new landscape orientation support for iPhone, and native interfaces for iPhone 6 and iPhone 6 Plus.

This is my first iOS 8 release and I'm hard at work updating Academy Coins and Bug Trackr to take advantage of new iOS 8 features. More on that in the coming days.

If you have feedback about iSource 2.5 please contact me through the about section in the app.

Thanks for your continued support!