Weekend Project: iOS5 Storyboard + Parse.com + Heroku Awesomeness
[UPDATE] Demo application source code avaialble GitHub, add comments there please.
While the rest of the family was eating their fill of Turkey and giblets, we received an enticing request via Kyle Bragger's excellent TinyProj to create a combined iOS app plus server backend for a cool "video greeting card" service. We had been looking for an excuse to try Parse.com and the new iOS5 "Storyboard" features and this seemed like an excellent chance to try out some new ideas, and get paid (thanks Satjot). And so we dug in!
First, the iOS5 Storyboards feature is a new productivity library & tool available within XCode 4.2 to solve the most common rapid prototyping problems, and to provide a flexible framework for "standard" navigation apps.
Second, Parse.com is a library and platform for rapid development of cloud-based apps which provides a flexible API, available under iOS, Android and through a RESTful interface, to enable user provisioning, general and relational data store and asset (image, audio, video) upload and synchronization using Amazon S3.
Lastly, Heroku is, well, Heroku.
Our Fieldforce app is a group-based chat and productivity tool which combines real-time messaging with cloud-based synchronization of contacts, and other "assets." We've been studying Parse.com to see if it could replace our backend. And while we have yet to determine if the newly released "Access Control List" may provide the type of complex user and asset provisioning that we need, for a "video greeting card" app, it seems to be a perfect match. Parse.com provides, out of the box:
Basic user authentication (account CRUd)
Object synchronization across devices (card metadata CRUd)
Asset upload & relational data mapping (video message upload & association)
Password authenticated RESTful access to objects & assets (video asset sharing via S3)
iOS5 Storyboards probably isn't the best for custom navigation controllers (eg., Open Springboard) but seems to work well for standard UINavigationController or UITabBarController based apps. Specifically for this design, and perhaps especially for iterative client work, Storyboards provided a nice way to quickly stitch together a rough flow of high-level views and determine the best (minimum?) set of views. We used the following approach:
Create the basic "top-level" flow using generic view controllers
Work with "unconditional" segues first, you can easily add conditions later
Build conditional segues using specific "dummy" buttons, not programmatically
Use the IB widgets for UITableViews and UITableViewCells, they're getting better!
Add conditional segues later, may need to "undo" the older segues
Use iOS5 UIAppearance protocols to skin the app
Deploy with the awesome TestFlightApp.com and their new SDK
Get serious about TDD and use Square's KIF test framework
Ok, we didn't quite get to TDD this time but we really, really want to... one of these days. (Heard that before?)
Finally, we tied the whole thing together using a simple Rails-based Heroku web app which basically parses a hashed URL to display a static "card" image and pulls the video asset from the Parse.com RESTful interface, which is acting as a front-end to the Amazon S3 services.
Some key lessons & learnings below. We can post a follow-up tutorial if there's more interest.
Parse.com setup was about as simple as could be, with the exception of the unfortunate namespace. Regardless, Parse.com allows you to set up data structures passively, without a prior database schema. This is nice in that it allows for experimentation on the app, to add new fields (columns) and objects as needed. The only setup to do on the Parse.com website is to generate the app keys.
We had an issue with the automatically generated SDK "starter kit" produced by Parse.com, as it's not compatible with iOS5 Storyboards, which James at Parse tells me they're going to update. But it was easy enough to pull the Parse.com SDK into a blank Storyboard app and use that as our starting point.
We started our app development with no user provisioning at first, and Parse.com supports this type of global or "application level" data objects. It was helpful to not force user registration at first, as we could focus on object (card) creation flow instead. The object metadata needs to be constructed use the typical data objects (NSStrings, NSNumbers, NSDicts, etc.), and, as you would expect, data objects can contain references to previously saved objects. This caused some trouble in the flow of the app in that you have to first store an object before it can be associated. If not, the Parse.com library throws an immediate exception which is ok but means we were left wondering what caused a crash or two when simulator our code. Better exception handling in the Parse.com library would help, a verbose NSLog output please?
One of the things we liked about Parse.com was the use of a RESTful API to access the saved objects, including access to the uploaded (video) assets. It wasn't clear from the documentation, but they upload assets to Amazon S3 and provide a publicly accessible URL which is immediately available from the +objectURL method call. This meant it was trivial for us to then share those assets with registered users. (Perhaps you can lock these assets down with the new Access Control List features, although it's not clear how this translates to S3 permissions).
Finally, we could uniquely determine the an object hash, again, after the data objects are stored on Parse.com, and we could use this hash to then reference our users' assets and metadata by leveraging the Parse.com RESTful API. Interestingly, this allows us to present the user with a simple static URL they can share. We can just query the RESTful API to pull all the relavant assets. No redundant data store needed. Sweet.
Parse.com User Authentication With Storyboard
Once we had data object construction working, we needed to create a user authentication flow. With Parse.com, this means you need to create, populate and save a PFUser object. This is a unique object within the framework which has some standard fields (columns) but also can be extended to store, for example, some business logic for perishable items which we then used as a trigger for our In-App Purchases.
With iOS5 Storyboards, the PFUser object creation looks something like the following:
The various ingress segues are to allow the user to signup from multiple points within the app, which allows for passive onboarding whenever the user feels ready to commit. The egress from login view to "Signup" is triggered by the UIButton, as is the "Forgot Password" egress.
All that remained was to add code to the "Login" and "Signup" buttons to sanity check the entries and then stuff the values into the Parse.com API calls for PFUser registration. The API calls are typically one lines calls, using Cocoa Blocks. The bulk of the code is actually error checking & UI animations. Nice to have the server code so painless for once!