Callum Jones
What I’ve learnt about iOS development as a Rails developer

I recently released Extended, a SoundCloud client aimed at handling long tracks such as DJ sets. I built this because the current SoundCloud client does not keep track of positions, causing you to loose your place if the app is killed or you switch tracks.

The precedent

My background has predominantly been web focused, during university I helped build internal apps for a energy/rail company before a brief stint at Rummble working on a simple crowd sourcing recommendations tool.. In my last year I flirted with iOS development helping build an application for our state ambulance service before moving internally to extending a ASP.NET MVC application.

After university I joined a risk company helping build out their Rails application to accomodate client specific needs (evening experiencing the joy of travelling to beautiful Switzerland) before landing at what has been my most joyous employment to date: Discovr. Discovr was excellent team blend, combining powerful backend infrastructure with an exciting iOS application and promising web frontend. Sadly Discovr hit some issues and the company was wound down, but it and Darcy, Stu, Dave, Chris, Ben, Matt & Matt taught me a lot about application scaling, API design, how startups should work and iOS development.

The itch

I’ve recently started to going to the gym more frequently and I’ve been enjoying extended sets from the likes of Above & Beyond, Eric Prydz and Thomas Gold but I found the existing SoundCloud unable to keep track of positions during application kills or track switching. This led me to believe I could potentially write my own app for iOS in Obj-C.

Objective-C?

If you like Ruby you might be tempted to write your application in Rubymotion. I’d recommended against it as this is your chance to get as close as possible with the device and platform you’re building for. Learning Objective-C will make you aware of the limitations of a mobile device that rightfully lacks a garbage collector and understand Apple’s SDK better.

Once you’re aware of Objective-C then feel free to switch on to RubyMotion, but it’s at least wise to understand what you’re building on. It’s good to experience the world outside of Ruby and deal with statically typed languages.

Embrace Objective-C’s verbosity, it’s an excellent way to communicate publically what a method call does. It makes more sense when you have multiple methods that expand on each other to provide additional context.

The initial setup

You’ll want to check out Cocoapods if you plan on using anything other than the native Apple libraries, it’s like bundler but for Xcode projects. It’s available as a gem and will walk you through the process of setting up compile references.

I’d really recommend paying the iOS development subscription to Apple, the iOS simulator is fast but there’s nothing like feeling the interaction between your finger and the code. You should be able to use the Organizer (Window > Organizer) to ensure your device is prepped for testing.

Skinny controllers

As for laying out your application I’d recommend the skinny controllers approach that is quite popular in modern Rails development. Your view controllers should deal with handling view rendering and view/event interaction while forwarding anything complicated to a manager.

For example: LibraryViewController in Extended asks LibraryManager for an array of the top 100 SoundCloudLibraryItems and then deals with rendering them in a tableview. It does not deal with any database queries, that is the manager’s job. The library manager also concerns itself with pulling changes from the SoundCloud API, it sends out a NSNotification via NSNotificationCenter when any data is changed and the ViewControllers subscribe on load and respond with refreshing their caches and the tableView.

The same goes for SoundCloudAudioPlayer: the LibraryViewController receives a tap event, it looks at its local cache of items and notifies LibraryManager that it wishes to play that item, the manager then calls the audio player.

Skinny controllers goes a long way to making your code reusable, testable and ultimately better to share amongst a team.

UI

In the future I’m going to really focus more on developing interfaces with code and less with Xcode’s storyboard and autolayout functionality. As a developer I’m interested in debugging the decisions that made my UI elements shift (watch out for 3.5inch devices and the call status bar) and sadly storyboard and the like hide that from me. With UIs developed in code you can instantly see where your positioning is being set and any changes you may need to combat.

Storyboarding still feels quite buggy during development in Xcode, I found cases where I’d scroll to the bottom right and then be kicked back to the top left.

This is a must read on choosing between when to code and when to IB.

When it comes to rendering items such as a view or UITableViewCell you want to be as quick as possible, don’t go to the database to fetch data instead try to have the previous view keep a cache of the data and then pass the objects onto your new view. For UITableViewControllers I have the initial load of a table fetch a cache from the Manager and then subsequent calls for each cell just hit the local cache.

If you’re terrible with simple icons like a heart or a audio player icon then you’ll want to grab some a glyph set and import them using this guide.

Don’t be a jerk

You’re building an app that runs on a incredibly personal device, you should feel privileged to be consuming the user’s time.

Assume and own resources when you need them on-demand. Don’t grab everything or request permission for everything when the application loads, you want the user to boot up your application with a smooth transition that does not feel foreign.

If you want to begin ownership of the Audio system for say playback, begin owning on the first playback and not when your app launches. A lot of applications own it at first launch, causing anything the user is currently playing to be killed! That’s one sure way to piss off a user.

Same goes for permissions, only ask for push notifications or location updates when you need it. Imagine being bombarded with UIAlerts when you first launch, it’s incredibly overwhelming.

Singletons

Because I really only wanted one SoundCloudAudioPlayer for the lifecycle of the application I made use of the singleton pattern for these types of classes (Managers as well). This allowed view controllers to not worry about using say the AppDelegate for coordination of the “current” player, they just had to ask the class itself for what is the current instance.

Delegates

If you’re following the skinny controller method you might want one instance to ask another instance questions, for instance SoundCloudAudioPlayer will ask the relevant LibraryManager what the next track is coming up.

To achieve this you can setup a class that is told about a delegate. This delegate promises to conform to a contract, a select implementation of certain methods. The class told about the delegate only cares about the methods specified in the delegate, so the delegate can implement any other methods or even other contracts. These contracts are called protocols, in summary:

  • SoundCloudAudioPlayer has a property NSObject<PlaylistHinting>* delegate.
  • SoundCloudLibraryManager : NSObject<PlaylistHinting> declares it implements the protoctol PlaylistHinting.
  • PlaylistHinting is dead simple.
  • SoundCloudLibraryManager can do a lot of other methods outside of delegate stuff.

Delegates are incredibly important when you being making network requests, you create and kick off off a network request and later the network request will call a delegate with the connection result. In this case usualy the delegate will be yourself.

Ruby comforts

Good news, Objective-C has blocks! If you want to enumerate objects you can easily do something like this [someArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { //some code }];.

Objective-C like Ruby operates through sending messages, if you wish to send things to an instance you can get dangerous pretty easily thanks to @selector() or NSSelectorFromString which you can send to an object via [self performSelector:<#(SEL)#>]. Or if you want to get even crazier you can performSelectorInBackground.

If you looking for some comforts around Enumeration this looks pretty promising.

Database

For the ambulance project I while back we were working with CoreData which can best be described as a relational object database. It’s certainly nothing like ActiveRecord and may not be best suited to your application needs, it’s somewhat complicated but has a lot of intelligence under the hood for migrations and relational mapping.

As I wasn’t needing complicated data storage I opted for Marco Arment’s FCModel, it’s a nice library on top of SQLite that does away with worrying about relational mappings or migrations. Instead you are writing classes much like ActiveRecord/Model, creating the migrations yourself and then querying them using plain old SQL. This fits my needs perfectly: I just needed a place to cache tracks from the SoundCloud API without any need for maintaing relational mapping.

You’ll find FCModel has the convenience of ActiveRecord’s callbacks, check out the implementation here to learn what callbacks you can subclass. I found myself subclassing save and create callbacks to correctly set the createdAt and updatedAt timings much like AR does.

If you find you enjoy migrations I’ve started extracting my migration library for FCModel in which you specify your migrations much like Rails migrations are performed, in code.

So for some FCModel might not do enough, but if you’re interested in just keeping local copies of data and enjoy the freedom of controlling your own SQL queries then give FCModel a try.

Backend (server) components

Extended has a basic Explore tab that allows people to view tracks that I’ve curated from SoundCloud, it’s good for those who don’t have a SoundCloud account or want to justify the price of a 99cent app.

Extended has no public endpoint and no administration panel.

Discovr had a huge infrastructure behind the client application, it had a large set of workers bringing in external data, a robust and extensive API for client operations and growing admin panel for data corrections. I wanted to avoid the hassles of scaling out my backend if Extended some how became popular.

So I’ve turned to AWS S3. Usually in most apps clients would hit a Rails application for a delta update since a specific date point, leaving the database to be optimised around last updated/inserted. While ExtendedData also maintains a database to record which tracks I’ve selected for curation it regularly publishes a diff to an S3 bucket for the clients to consume. The flow looks something like this

  • A Google spreadsheet is looked at for the curated SoundCloud accounts to check
  • An import process looks for any new tracks published by those selected number of SoundCloud accounts
  • An second import process looks at my own personal sets for new playlists to add
  • The export process looks at latest.json in S3 for the last time the export was published grabs the tracks newer than that date. If there is nothing new, the process quits.
  • Any new items are published into a new latest.json and the old latest.json is moved to the date it was published (eg 1395061443.json), with latest.json containing a key that points to the previous latest.

The clients then hit latest.json and following the linked JSON files for up to a depth of 8. If at anytime they see a file that they have processed before they bail out and record in a simple KeyValueStore model what the most recent processing was.

You could say latest.json behaves like a linked list.

Test

Test on both the simulator (in both sizes) and your device. Assume the simulator is bug free and your code is wrong until you can prove otherwise, I made the mistake of casting a 64bit integer badly causing it to work fine on my iPhone 5S and then see weird time rendering on the simulator. It wasn’t until I tested on a non 64bit ARM device that I found out I had screwed up and had been stupidly thinking the simulator is buggy all the time.

  • Test with the in-call status bar. Try switching it on during the application and try having it on before the application launches and then see how your UI responds when it goes away. You can do this on the simulator otherwise you can try tethering.
  • If you’re doing anything network, try your app with just WiFi and then try switching off the WiFi and leaving no internet available. I’m using NSNotifications sent to the TabBarViewController to rendering a error notification that scrolls in from the top. I’ve added Reachability for knowing when the network returns.
  • Turn to Testflight for distributing test builds, you’ll want to read this document on how to setup Ad-Hoc profiles (hint: you can’t use Xcode Organiser well).
  • Use Safari for the iOS Dev portal, it sometimes loads in-secure resources that cause Chrome to kill requests such as adding a device (it still adds it but the view loading hangs).
  • Setup Bugsense or Crashlytics for tracking your crashes, in the case of Crashlytics make sure you sign up well ahead of time as they operate on an invite only basis.

Be rough with your app: open and close views and watch how well your app manages resources. If you see ballooning between view loading with not much reduction after a period then step through init code and see if you need those resources.

As for automated tests, I’ve been using XCTest for various parts but I can’t comment much on it at this stage. SlimMigration makes use of XCTests here.

App Store

I found the App Store submission process great, just be prepared for a lot of uploading as the screenshot uploader lacks a multi uploader.

Assume that the reviewer has no way of creating any external accounts, I found my app rejected because I failed to provide them with a SoundCloud account. After correcting that and resubmitting the new metadata it was less than 23 hours before I was in the store.

Why the NBN needs go the full way.

I’ve always been unsure how I’ve felt of the Liberal NBN plan vs. Labor NBN plan. After being prompted to think about I think I’ve finally decided why a half assed solution isn’t good enough this time.

No. Fibre to the premise has very little to do with speed/waiting times and people need to drop this stupid reference, it’s a backwards way of looking at how a new technology evolves.

Fibre removes the bottleneck for any future technological movement in Australia. It enables any business to compete globally from just a standard home connection, right now at work we are stuck on an aging 4mbit ADSL connection — this prevents us from bringing our 200GB remote database in locally for development and testing. Some of us have to go home if we ever want to check out the latest 5GB iTunes catalog dump.

Fibre switches on the capabilities for medical imaging, especially in remote areas. Fibre switches on the dream of being able to live in the cloud, you only need a simple buffer on your iPad with everything else on your remote device.

So right now we have two ways of measuring ‘speed’. Latency is how long it takes for data to get between two points and bandwidth is how much we can push between the two points in that time.

Because fibre is light based, the latency is incredibly small - it would be like the computer was in the same house if you were communicating in WA or Australia. This enables industries to cross collaborate in a way we have never seen before.

Want access to a raw footage library? With fibre you can be at home and have a very reliable experience.

Want to work from home and have the same level of access to your work network as you do at home? With fibre it would be like you were in the same office.

Fibre to the premise switches on so many opportunities it’s impossible to grade it by ‘waiting times’.

The Pebble watch is an exciting sneak peak

I’ve had my Pebble watch for around a week or two now, and I am very excited by it. I’m excited by not only what it can do now at it’s price but by what it represents the future can do with compact connected devices.

I see the Pebble as the introduction to idea of small & compact networked screens that complement our existing devices. The Pebble’s main advantage is that it has access to a phone providing it with with an always on network connection and a very fast processor.

I see the phone as the Pebble’s gateway to the connected world, not just a forwarder of notifications.

A smart watch will be addressable directly

Right now we are hacking notifications to our phones (via services like Pushover) but a watch like the Pebble will need to exist on its own and events should be publishable directly to it. There are things that are relevant to me that change between the context of my phone and my watch.

A smart watch shouldn’t receive all phone notifications

The idea that you will see all your email on the watch is going to kill the smart watch. No one wants email tied directly to their wrist, we should be taking the idea of Gmail’s Important or Apple’s VIP email and applying it to email notifications on the device.

Vibration should respect event severity

A phone vibrating is annoying, I’ve switched it off in Silent mode just so I can have a way to kill my phone’s annoyances.

A smart watch should receive more context about the notification to understand whether or not a vibration is required. Phone call - yes Email - maybe SMS from VIP - yes SMS from a group - No.

It should be thought of as a passive device

We can become addicted to a Dick Tracy phone that has all the bells and whistles such as talking to it or using it as a calculator — or we can build something that complements our networked world.

The watch can be something that receives contextual information based on our phone’s location such as routing information, important alerts and it can be something that prepares us for the future with upcoming & important information.

If I’m walking to a meeting, it could provide me route guidance if I veer off course on the streets.

If I have events coming up it can prepare me and guide me so I’m there are ready on time.

It’s not like what we tried before

Microsoft/MSN tried to build a watch that provided the weather, sports & news. It didn’t sell because society at the time wasn’t into the idea of connected devices — we had not been shown the power of the iPhone with notifications.

The old watches were set in the things they could do, they could be relevant to people other than a select group of people who wanted News + Weather + Sport. People now want information tailored to what they care about, not a generic template for everyone.

Really nice simplistic demonstration video from Mercedes-Benz, I really like videos that scrap all surroundings to the basics to focus on the product.

I appreciate that they struck the right balance as well, the background scenery is still animated and stuff is still going on (like cars going under bridges).

This is the concept for the BMW 4 series coupe.

What really excites me is that the design of this car connects the front and the back, it looks good from any angle.

This is the concept for the BMW 4 series coupe.

What really excites me is that the design of this car connects the front and the back, it looks good from any angle.

The third type of email: external things

I was reminded to revisit the .Mail concept by Tobias van Schneider and it got me thinking about the third category of emails where they don’t quite fit into actionable tasks and they aren’t really things you want to revisit later.

References to external things

Flight e-tickets, courier tracking numbers; these are the sorts of things I don’t particularly want an action for but rather have them become useful at their declared date.

An email is now more than just a collection of text, it’s used as a referenced to external objects (hyperlinks) but why should we jump from an email client into a website to extract information that could have been embedded in the email. What if that email was live, those external objects behind the email were being updated inside our email client and we didn’t have to click through?

And why should something that may not be needed now but needed later be buried underneath newer emails?

E-tickets

In the case of an e-ticket I want it to setup a reminder for me to leave for the airport and I want it to become useful when I’m in the airport. This sounds like Passbook but unlike Passbook it doesn’t require any action or handling of special .pkpass files; the client recognises an e-ticket and organises it appropriately without you having to manually invoke a workflow.

Passbook currently extracts that e-ticket and stores it in a segregated data store (iCloud), meaning you’re out of luck if you’re roaming and have access to a internet cafe but no WiFi for your iOS device. The e-ticket (metadata in the email) should be stored with your email so when you visit Gmail/iCloud/Outlook online in a cafe you should be able to see a richer email with details about your flight, changes etc

Courier tracking

But I’m more interested in the courier tracking numbers, these only become useful after a few days but after a few days you have to hunt through your emails to find that tracking link. A mail client should be capable of subscribing to this courier tracking number and polling for updates, when the package is in your city you should be subtlety notified but when the package is out for delivery your mail client should delivery a notification to you.

Push?

Maybe it shouldn’t be polling that the mail client has to do, maybe email providers should be pushed updated meta-data for a specific message? To establish the push link

  • The mail provider sees an email with external objects
  • Communicates with the external objects provider, declaring this how you can reach me
  • The external objects provider can then push updates/events to the related mail message

By using the email provider we don’t have the issue of OS X doing its own thing with the provider, my iOS device doing its own thing etc. They are just receiving the information from the middleman email provider.

From there a company like Emirates could push a generic event that contains a date & time (okay awesome let’s create a calendar event) or they could push an important notification (okay we may need to update the calendar event and flag the mail to the top regarding a flight change).

A company like UPS could push a notification (a casual bump for that message that the package is in my city) and another important notification (flag the email and send out a push notification).

There does come the problem of spammers having an essentially having a richer way to spam you, so we might have to look into human verification where we have an established list of services that are trusted for pushing to email providers. Again the email provider can chose to blacklist bad push providers.

What are we achieving here?

  • We aren’t diving through emails to find things when we need them. Those emails are presenting themselves when circumstances change and becoming useful when we need them.
  • We aren’t locking the richness of an email to something like passbook on an iPad or iPhone, we are letting an external or web mail client be just as useful. And we are letting people move between Android, WP8, iOS without locking away important rich content
  • We are turning email into an important organisation tool

Beautifully simple furniture design.

Keep physical things physical.

This post isn’t meant to be a guide or a essay, it’s really just an admission of guilt about my incorrect love for a worrisome UI paradigm. I’m writing this because I believe design and connections (with people OR systems) are the most important things in life

I was recently very excited to install an app called Weather Dial, an app for the iPhone that provides an overview of the weather in a design based off the design principles of Dieter Rams. It’s meant to look like a Braun product but it’s trapped inside a phone and I’m really over it.

I was originally attracted to it because of my interest in Rams’ work but I’m really feeling let down by the application because of the box it locks itself into and limitations it reaches because of this.

This app has a huge dial that indicates the type of weather currently, it even animates like a mechanical wheel. But, I can’t play with itself despite my mobile having this touchscreen so I’m left with a view into a world containing a product I can’t really touch (it even feels like a magical world because it’s told iOS to get rid of my status bar so who knows what the time is in this new magical world). I love design because it’s usually connected with its environment, a beautiful Braun watch face is linked to a nice band and it feels great but I’m left with a app that ends with the size of the screen — but I can’t turn over my phone and feel the back of this weather machine.

I feel like this design is probably more about being cool or showing off appreciation for elegance, when design (for me) is about helping people get stuff done in life. Machines are meant to be out of the way.

I truly appreciate the core reason of skeuomorphic design, trying to build interfaces that people can relate to and be able to use without any hesitation. But it locks your application into a very tight box that you can’t get out of, it leaves no room for growth because the physical product has already been decided in its functionality and going beyond that would be a departure from the product itself.

So.

We should limit skeuomorphic design to the concept of building things that people can relate to, but don’t base a look or feel off it. Why is a notepad and paper so successful? It’s because it marries a easy to use input device with a responsive way of storing information. So let’s build off this in an application, build an easy to way to input data easily with a powerful way to store information. Dump those truly terrible cursive fonts (hey, Notes in iOS thank you for introducing Helvetica as a input font).

I’m interested in design teaching people how to use modern day devices without having to rely on a manual or previous experiences because not everyone has those previous experiences.

We need to keep pushing computers forward. We’ve done this in the hardware world by dumping floppy disks, DVDs but keeping software in touch with the past is going to leave a dull future.

This is still my favourite application design.

Mercedes CLS63 AMG Shooting Brake

You&#8217;d be crazy to buy a Porsche Panamera over this, it seems Mercedes actually thought about a good design for a estate wagon. Whereas the Panamera (like every other Porsche) seems to be an lazy extension of the 911 design.

Mercedes CLS63 AMG Shooting Brake

You’d be crazy to buy a Porsche Panamera over this, it seems Mercedes actually thought about a good design for a estate wagon. Whereas the Panamera (like every other Porsche) seems to be an lazy extension of the 911 design.

BMW M135i

I don&#8217;t think anyone can deny that hatches are the most exciting form factors right now.

BMW M135i

I don’t think anyone can deny that hatches are the most exciting form factors right now.