Siri Integration in iOS 10 with Swift – SiriKit Tutorial (Part 1)

Siri integration on iOS 10 – Swift Tutorial

This tutorial written on June 13th, 2016 using the Xcode 8 Beta 1, and is using the Swift 3.0 toolchain.

Get Xcode 8 set up for iOS 10 and Swift 3 compilation.

If you have not yet downloaded Xcode 8 Beta 1, please do so here.

(Optional) Compiling from the command line

To opt in to the Swift 3.0 toolchain you shouldn’t need to change anything unless you want to build from the command line. If you plan to build from the command line, open Xcode-beta and from the OS menu bar select Xcode > Preferences. Then select the Locations tab. At the bottom of the page here you will see “Command Line Tools”. Make sure this is set to Xcode 8.0.

Now if you navigate to the project directory containing the .xcodeproj file, you can optional compile your project by calling xcodebuild from the command line.

(Optional) Migrating from an existing Swift 2 app

If you are working with an existing Swift 2 project and want to add Siri integration with Swift 3.0, click on the root of your project and select Build Settings. Under Swift Compiler – Version, find the field labeled Use Legacy Swift Language Version and set it to No. This will lead to compiler errors most likely that you will need to fix throughout your project, but it’s a step I recommend to keep up with Swift’s ever-changing semantics.

Getting started with SiriKit

First, in your app (or in a new single-view Swift app template if you are starting fresh), switch to the general view by selecting the root of your project. Under this tab you can click the (+) icon in the lower land corner of the side-pane on the left. From the dropdown that appears selection iOS > Application Extension, and then select Intents Extension.

Select Intents Extension

This adds a new intent to the project, and we’ll use it to listen for Siri commands. The product name should be something similar to your app so it’s easy to identify, for example if your app is called MusicMatcher, you could call the Product Name of this intent MusicMatcherSiriIntent. Make sure to also check the checkbox to Include UI Extension. We will need this later in the tutorial, and it’s easiest to just include the additional extension now.

Intents Extension Options

What we’ve created are two new targets as you can see in the project heirarchy. Let’s jump in to the boilerplate code and take a look at the example in the IntentHandler.swift file inside of the Intent extension folder. By default this will be populated with some sample code for the workout intent, allowing a user to say commands such as “Start my workout using MusicMatcher”, where MusicMatcher is the name of our app.

IntentHandler.swift

Run the Template App as-is

It’s helpful at this point to compile this code as-is and try out the command on an actual iOS device. So go ahead and build the app target, by selecting the app MusicMatcher from the Scheme dropdown, and when the target device set to your test iOS device, press the Build & Run button.

Select the MusicMatcher target

You should see a blank app appear, and in the background your extensions will also be loaded in to the device’s file system. Now you can close your app using the Stop button in Xcode to kill the app.

Then, switch your scheme to select the Intent target, and press build & run again.

Select the MusicMatcherSiriIntent target

This will now prompt asking which app to attach to, just select the app you just ran, MusicMatcher. This will present the app again on your device (a white screen/blank app most likely), but this time the debugger will be attached to the Intent extension.

Select the app to run with the extension

You can now exit to the home screen by pressing the home button, or the app may exit on it’s own since you are running the Intent and not the app itself (This is not a crash!!!)

Enable the extension

The extension should now be in place, but we as an iOS device user still may need to enable the extension in our Siri settings. On your test device enter the Settings app. Select the Siri menu, and near the bottom you should see MusicMatcher listed as a Siri App. Make sure the app is enabled in order to enable Siri to pick up the intents from the sample app.

Testing our first Siri command!

Try the Siri command. Activate Siri either by long pressing the Home button, or by saying “Hey Siri!” (note the “Hey Siri!” feature must be enabled in the settings first)

Try out some of the command “Start my workout using MusicMatcher”.

“Sorry, you’ll need to continue in the app.”

If you’re like me this will bail with an error saying “Sorry, you’ll need to continue in the app.” (For some reason this occassionally was not a problem. Ghosts?)

In the console you may see something like this:

dyld: Library not loaded: @rpath/libswiftCoreLocation.dylib
  Referenced from: /private/var/containers/Bundle/Application/CC815FA3-EB04-4322-B2BB-8E3F960681A0/LockScreenWidgets.app/PlugIns/JQIntentWithUI.appex/JQIntentWithUI
  Reason: image not found
Program ended with exit code: 1

We need to add the CoreLocation library to our main project, to make sure it gets copied in with our compiled Swift code.

Select the project root again and then select your main MusicMatcher target. Here under General you’ll find area area for Linked Frameworks and Libraries. Click the (+) symbol and add CoreLocation.framework. Now you can rebuild and run your app on the device, then follow the same steps as above and rebuild and run your intent target.

Finally, you can activate Siri again from your home screen.

“Hey Siri!”
“Start my workout using MusicMatcher”

Siri should finally respond, “OK. exercise started on MusicMatcher” and a UI will appear saying “Workout Started”

MusicMatcher Workout Started

How does it work?

The IntentHandler class defined in the template uses a laundry list of protocols:

First an foremost is INExtension which is what allows us to use the class as an intent extension in the first place. The remaining protocols are all intent handler types that we want to get callbacks for in our class:

INStartWorkoutIntentHandling
INPauseWorkoutIntentHandling
INResumeWorkoutIntentHandling
INCancelWorkoutIntentHandling
INEndWorkoutIntentHandling

The first one is the one we just tested, INStartWorkoutIntentHandling.

If you command-click this protocol name you’ll see in the Apple docs this documentation:

/*!
 @brief Protocol to declare support for handling an INStartWorkoutIntent
 @abstract By implementing this protocol, a class can provide logic for resolving, confirming and handling the intent.
 @discussion The minimum requirement for an implementing class is that it should be able to handle the intent. The resolution and confirmation methods are optional. The handling method is always called last, after resolving and confirming the intent.
 */

Or in other words, this protocol tells SiriKit that we’re prepared to handle the English phrase “Start my workout with AppName Here.”
This will vary based on the language spoken by the user, but the intent will always be to start a workout. The INStartWorkoutIntentHandling protocol calls on several more methods, and they are implemented in the sample code. I’ll leave you to learn more about them if you want to build a workout app, but what I’d rather do in the remainder of this tutorial is add a new intent handler for handling the sending of messages.

Let’s Add a New Message Intent

Now that we’ve confirmed that works, let’s move on to adding a new type of intent for sending messages. The docs here show the following:

Send a message
Handler:INSendMessageIntentHandling protocol
Intent:INSendMessageIntent
Response:INSendMessageIntentResponse

So let’s add the INSendMessageIntentHandling protocol to our class. First we’ll just specify we want to use it by appending it to the list of protocols our class adheres to in IntentHandler.swift. Since I don’t actually want the workout intent’s, I’ll also remove those, leaving us with just this for the class declaration:

class IntentHandler: INExtension, INSendMessageIntentHandling {
    ...

If we just left it at that we wouldn’t be able to compile our code since we stil need to implement the required methods from the INSendMessageIntentHandling protocol.

Again, if you ever need to check what those methods are, just command+click the text INSendMessageIntentHandling and take a look at what method signatures are present that are not marked with the optional keyword.

In this case we find only one required method:

/*!
 @brief handling method
 
 @abstract Execute the task represented by the INSendMessageIntent that's passed in
 @discussion This method is called to actually execute the intent. The app must return a response for this intent.
 
 @param  sendMessageIntent The input intent
 @param  completion The response handling block takes a INSendMessageIntentResponse containing the details of the result of having executed the intent
 
 @see  INSendMessageIntentResponse
 */
public func handle(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Swift.Void)

Adhering to the new Message Intent protocol

So back in our IntentHandler.swift, let’s add a line seperator (useful for navigating code with the jump bar)

// MARK: - INSendMessageIntentHandling

Underneath this MARK, we can implement the function. I find it’s most useful with Xcode 8 to simply begin typing the method name, and let autocomplete take it from there, choosing the relevant option.

Fill out the handle method with autocomplete

In our handler, we’ll need to construct an INSendMessageIntentResponse in order to call back the completion handler. We’ll just assume all messages are successful here and return a success value for the user activity in the INSendMessageIntentResponse constructor, similar to how this is done in the template app. We’ll also add a print statement so we can see when this handle method is triggered by a Siri event:

func handle(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Void) {
    print("Message intent is being handled.")
    let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent))
    let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
    completion(response)
}

Adding the intent type to the Info.plist

Before this app will be capable of handling INSendMessageIntent, we need to add the value to our Info.plist. Think of this as something like an app entitlement.

In the Info.plist file of the intent, find and expand the NSExtension key. Then extend NSExtensionAttributes, and then IntentsSupported under that. Here we need to add a new row for our INSendMessageIntent to allow the app to process Message intents.

Add support for INSendMessageIntent aka messages intent

Testing the new intent

Now that we’ve got our new intent set up, let’s give it a try. Recall that you must build the app, run it on the device, and then run the extension in order to debug the extension. If you don’t do run in this order the extension will either not work, or it will not log to the Xcode console.

Try calling upon our intent in Siri, and you will now see a new message window appear! The window is pretty empty, and there isn’t much logic to tie in to our app just yet. We need to implement the remaining callbacks and add some of our app’s messaging logic to provide a better experience. We’ll cover that in Part 2, which is available now. If you want me to email you about it when other tutorials come out as well, sign up for my newsletter to get the scoop.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Mobile First & Declining Usability

Mobile App Design is Fashion

Mobile app design moves very quickly, and with “mobile-first” thinking becoming the mantra of designers of all kinds, it is a leading indicator for design of just about everything else. So, I think it’s important to take a step back and analyze how apps are designed today. In this I break down the most recent mobile app design trends that I believe are actually hurting us, and making our software worse.

The way mobile app designs is very much a fashion-of-the-week type of situation where the target changes on a nearly daily basis. What was cool a month ago is stale in comparison to today, I use the term “fashion” to generally describe this reality. Before we dig in to the specifics of modern app design, let’s talk a little about fashion itself.

Fashion is irrelevant

I recently found myself reading an essay by Milton Glaser, one of the world’s most celebrated designers. In the essay he talks about “The Bull” by Pablo Picasso. In the work, Picasso renders 11 different variations of a bull each in differing styles. The work ranges from the realistic rendering, to a cartoon rendering, then to a more abstract cubist rendering, and finally simple line art.

Picasso: The Bull

As Glaser puts it, “What is clear just from looking at this single print is that style is irrelevant. In every one of these cases, from extreme abstraction to acute naturalism they are extraordinary regardless of the style.” – Ten things I have learned, Milton Glaser

I thought this line of thinking was very interesting. Glaser makes the point that “Style is not to be trusted”. Or another way to think about that, is that style is fashion, and it comes and goes with the tide. In demonstrating that the style of the work is actually irrelevant to it’s quality, we could draw the conclusion that style in ap design (the aesthetic) is also irrelevant, except for one small problem…

Fashion is of utmost importance

Back in the early days of smartphones the designers at Apple had a clear design goal: Familiarize people with touchscreens. So the style was glossy buttons with shadows, and controls that seem like they want to be touched. If there was a real-world analogue that could be used to symbolically represent a 3D interactive object, they would use it. This is known as skeuomorphism in the design communities, and I won’t rehash why everyone decided they hate it in the past few years here. What I will say however is that there was value in those old ugly interfaces. What we were able to do with skeuomorphism is train users to use our apps with visual language. The best example I can think of from those days is the picker view (called a UIPickerViewController in programmer speak).

UIPickerViewController

Nothing about the design of the picker view makes much sense, really. The only thing it does well is it looks like a spinning wheel, which encourages you to spin it like a contestant on The Price is Right. It’s kind of fun, in fact. But, this interface actually kind of sucks to use. You can only see about 4 or 5 options at any given time, and selecting a specific option requires a fine-tuning sort of interaction where you slowly and carefully align a value with the center of the view. A much simpler approach would be to just put options in a big fullscreen list; which is actually what Apple ended up using more often in their own apps. (Also known as a UITableViewController.)

UITableViewController

While these types of interfaces have many drawbacks, I have to wonder if my elderly friends, or my infant nephews would have been able to use smart devices so readily where they not using these metaphors for reality. Would smartphones have become as successful as they are now without skeuomorphism?

It wasn’t just this picker either, skeuomorphism informed the iBooks interface, designed to look like an actual bookshelf:

iBooks

It inspired the Calendar interface, to look like an actual calendar:

Calendar

And just for fun: Designer Meng To posted this skeuomorphic version of Facebook that looks like an actual book. on dribble.com

Facebook by Meng To

2016

Fast-forwarding to 2016, we have completely abandoned the idea that people don’t know what to do with touchscreens. I think we actually have gone too far. Have you ever tried to use Snapchat? It’s like they have made it intentionally confusing to use. Everything is hidden using gestures and invisible buttons you are supposed to know to tap and hold, and weird things like that. Some of the apps most interesting features are completely hidden from view.

There was a lot of positive reactions to the app Clear from a few years ago. It was a huge hit because of it’s unique UI animations. But here’s my question: How many of those downloads translated in to regular users? I don’t want to sit here and hate on the Clear app because I think it was a brilliant design in terms of being unique and fashionable. What it was not however, is usable.

Clear

Okay, so I swipe to the right to finish a task… Oops wrong one, how do I undo that? Do I just re-add it? Wait, how do I add a task again? Oh, I take two fingers and separate two existing tasks, and that makes a new one appear in between my existing ones? That’s odd… what if I don’t have two tasks? Do I just sort of “unpinch” the negative space where my tasks would be if I had two?

Yep.

That’s exactly what you’re supposed to do, and that sucks…

To clear a task swipe to the left, to finish a task swipe to the right. Wait, what’s the difference? I’ve cleared some of my tasks, but deleted others. Either way they get removed from my list…

If you go look at the app store reviews for Clear, you’ll see a lot of people complaining about the same thing, and I can’t even fully explain it to you because I don’t understand it either. But apparently if you perform a swipe gesture up (or down?) it will delete the entire list. How’s that for a fun and wacky gesture! So fun! You just lost your entire task list, which is the entire point of the app! That dismiss animation was sick though, so the app must be great, right?

Clear Reviews

The tutorial for Clear says I should “Pinch together vertically” to collapse my current level and navigate up. So instead of tapping a back button to navigate up, I have to perform a two-handed unpinch gesture for that too? I thought that was the gesture for creating a new task? HOW DO I USE THIS APP I DONT UNDERSTAND!? ARGGGH!!

deletes app…

Fashion sucks

As disappointing as it is, this seems to be the new fashion in apps: I summarize it basically as intentionally terrible user experience. I was talking to a prospect recently about an iOS App we were planning to help them build. They showed me a mockup that involved quite a few hidden buttons and gestures to control the UI. I carefully explained that users were unlikely to find these gestures and that we should move these things in to buttons that are more obvious. As a compromise, we needed at least a quick tutorial to show them these features. The response I received was surprising, to say the least:

We want this to be a secret

If we were designing a video game level this would maybe make some sense. It’s typical to “hide” some areas of play so that it’s rewarding when they are discovered. This is basically what they were going for. But for a mobile app, this is just a poor UI decision that is going to leave people confused. This wasn’t some kind of special easter egg hidden feature. This was basic functionality for switching to a friends list in the app.

You want to hide the friends list from users? This kind of thinking is now fashionable. Whether we like it or not, fashion influences the way we write software. As someone who is going to spend hours of my life building out these features, I hate the idea that most users simply will never find them. That’s why I declined that particular project. I left money on the table, but saved myself from spending time on work I didn’t find meaningful.

It’s our responsibility to fix it

I could sit around critiquing popular app’s designs all day (and I might), but this post wouldn’t be much use to anyone if that was all I did. So, let’s talk solutions…

1. Recognize that you can fix things

First, I think it’s important to accept that application developers have the final say in what their work ends up producing. You may think the decisions are simply made by your client, your boss, your partner, or your dog. Blame who you want, but your apps are the output of your efforts. If you are being boxed in to a corner and being asked to do something that sucks, you should stand up against it. You should learn to say “no” more often. At the end of the day, if you deliver what you think is best to solve the problem at hand, and you do your best work, no-one can complain about that. If they do, then they’re probably not worth working with anyway.

2. Do hallway testing

Hallway testing is the kind of testing you do when you grab some random person “out of the hallway” to test your app. You may have NDAs or similar agreements that make this a challenge, which is why it’s important to make sure agreements like this permit hallway testing. You may not be able to place an ad and have dozens of testers come to your office, but you can at least get family member or friend to try things out.

There are two very important aspects to hallway testing that are required for it to work. The first is that you absolutely can not explain things to the user while testing. It will be your first reaction to want to explain away any rough edges, defend your work, or try to help move things along to avoid embarrassment. This no longer represents a real hallway test though, this represents what it would be like if every user of your app was accompanied by you with your explanation, which obviously is not happening.

The second thing you must do is take notes of any stumbles. If you watch a user struggle with a component of your app for several minutes, and then finally figure it out, you could very easily write it off and say “oh well, they eventually figured that out so it’s not a priority”. WRONG! Your testers will have infinitely more patience than real-world users. If a tester is struggling, you need to make a note of it. Make several notes in fact, you’re going to forget if you don’t, and then those issues won’t be addressed.

3. Don’t hide anything inside of non-obvious gestures

If you are making a feature that involves swiping, pinching, or any other gesture, you should make sure it actually is intuitive to do so. For example, panning on a map (like an Apple Map) is very intuitive… it’s obvious that you would want to scroll the view and it’s obvious how you would go about doing that.

You’ll have to use your judgement on this one, but one way to confirm that your gestures are clear is by doing hallway testing, as mentioned above. You can trust your instinct with this stuff, but you also need to confirm you were right. Often something that seems intuitive to you will not be obvious to your testers.

4. Don’t be clever

There’s a famous quote often cited in software development projects.

Everyone knows that debugging is twice as hard as writing a program in the first place.
So if you’re as clever as you can be when you write it, how will you ever debug it?
“The Elements of Programming Style”, 2nd edition, Chapter 2

The same thing applies to user interface design. If it was a really clever idea, you should always be wary. Often the dead-simple obvious solution is the best one. This is basically just Occam’s Razor restated, which is often quoted for a reason: it’s true.

5. You tell me

What are the other takeaways here? How do you make sure your apps are highly usable? Tell me in the comments or on Twitter.

P.S. As an interesting side note, “The Bull” is also reportedly the subject of Apple’s training materials on their design thinking, for entirely different reasons.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

How To Migrate Your App And Protect It From Shutdowns Like Parse’s

How To Migrate Your App And Protect It From Shutdowns Like Parse’s


Editor’s Note: This article is written by Reinder de Vries, indie app developer at LearnAppMaking.com.

Oh no! Parse is shutting down… How do you move on?

On January 28th Parse announced it will be shutting down its service. They’re winding down the done-for-you Backend-as-a-Service, fully retiring it on January 28, 2017.

That’s bad news for over 500.000 developers who relied on the service since 2011. Like Jameson argued in his recent blog post, developers are feeling betrayed in their trust.

Parse was acquired in 2013 by Facebook for $ 85 million and now the “Big Five” monarch cold-bloodedly pulls the plug on the backbone of many developer’s apps.

Back in 2013 Parse was a risky acquisition, which Facebook needed to get a foothold in the mobile market. Facebook’s recent earnings report shows a growth in mobile advertising revenue of 52%, comparing Q4 of 2014 and 2015, which clearly shows they’ve landed in mobile.

With the rise in competition of cloud services by the likes of Amazon, Microsoft and Google, you could argue Facebook doesn’t need Parse anymore. From a business perspective I couldn’t agree more with them, but from a developer’s perspective it’s an awful move to make.

Or is it?

Parse’s Shutdown Is An Opportunity For App Developers

Before I built apps, I built websites. Lots and lots of websites. I learned all the necessary skills: HTML, CSS, JavaScript, PHP and MySQL. The quality and elegance of my code back then would make your skin crawl, but through trial and error I eventually mastered delivering quality websites.

Throughout the years I kept my craft up-to-date by building the occasional web app. Newer and more advanced tools became available and my job required I use them. I’ve transitioned from jQuery to Angular to React, touched on too many JavaScript frameworks in between, saw the rise of package managers and GitHub (SourceForge, anyone?), the switch from PHP 4 to PHP 5 to PHP 5.6 and the upcoming PHP 7. My MySQL tables exploded, so I switched to Elasticsearch and Mongo.

A while back I wanted to automate email newsletter signups and TestFlight beta invites. If you’d subscribe to the newsletter and confirmed your subscription, the workflow would automatically add you to my TestFlight pool of beta testers. I knew about the awesome FastLane toolset, and its boarding component, and figured boarding‘s HTML form must have a POST URL endpoint I could hijack. Essentially, I’d catch the subscriber’s email address from my form and input it into the boarding form. Boarding would take care of the rest, like adding the subscriber to the TestFlight beta tester pool.

There was only one problem: the boarding form had CSRF protection, which meant it expected a unique token to be included in every request. Those tokens are created server-side and in my workflow I didn’t have access to them.

I had access to boarding‘s source code, so technically I could solve the problem by disabling the CSRF protection. There was only one caveat: the source code was in Ruby, and I haven’t seen a single line of Ruby in my entire life (OK, maybe one), let alone have written one.

Thanks to my extensive background in back-end programming, I’m not afraid of getting my hands dirty with technology I don’t know. Years of tinkering and making mistakes gave me a perfect understanding of how the web works. Instead of shying away from a black box, I dug deeper.

I saw libraries I’d never heard of, with even stranger names (is this a thing?), and finally found the file that governed the CSRF protection feature. Ultimately, turning it off simply meant “nulling” a controller.

The Back-End Black Box

Almost every successful app uses some sort of back-end service to connect app users to each other, and persist user data on a server.

Many developers I meet and coach don’t have a solid understanding of back-end programming. Once they set up their Parse configuration in the overly simple Dashboard, write a query, they just assume their data is “out there”. Why would you bother finding out what happens in the cloud?

I often explain Parse as “a spreadsheet for your app”. It’s true: the Parse Dashboard isn’t more complicated than Google Spreadsheets, yet it powers the entire back-end of your app. You don’t even have to write queries for data, instead you use convenience methods like:

PFQuery(className: "Tweet").whereKey("user", currentUser);

It’s perhaps also Parse’s fault. Their PFQueryTableViewController is so incredibly easy to use, but pretty dangerous: it directly couples back-end code with your app’s view controller (which is already a ViewModel). Even if you wanted to switch from Parse to Firebase, your code is so tightly coupled you have to rewrite your entire app before you can migrate.

Parse’s PFObject class has mapping built in, so you can work with string data as native Swift String objects, while in fact the Parse SDK turns that into data it can send over the internet. If you pass around PFObject instances in your user-facing code, you’re going to have a hard time replacing that with a new Backend-as-a-Service SDK.

If you would have built your own back-end from scratch, you would have known for instance that true (a boolean) is sometimes turned into "true" (a string) when encoded as JSON. If that hits your app, you’re suddenly working with an instance of String instead of the Bool you expected. Fortunately Swift has an incredible type system, but an if let optional binding statement only protects against a type mismatch — it doesn’t resolve it!

So how’s this Parse shutdown good for you? It’s time to start tinkering again, to dig deeper into the black box and to protect your code against shutdowns like Parse’s.

3 Ways To Make Your App Shutdown Proof

Next time you build an app, keep these three heuristics in mind. Instead of relying for 100% on one provider whose service is vital to the continuity and success of your app, you can protect yourself against shutdowns.

1. Make a list of alternatives
Parse has a couple of similar providers, like Firebase. Perhaps you didn’t even know Firebase existed until you Googled for alternatives in reaction to Parse’s shutdown.

The cool thing is: most of these services know you’re looking for them. If you Google “parse shutdown” or “parse migration”, you’re hit with multiple highly relevant Google AdWords ads that tell you to migrate over to their service. Don’t do it!

Instead, make a list of alternatives. Just make yourself comfortable with what’s out there. It’s never a bad idea to have a list of providers you rely on, and their alternatives. Just like a supermarket has a list of alternative milk suppliers in case their main provider goes out of business, you should keep a list of companies you do business with.

You can of course also use the list of alternatives to do some proper research about the technologies and SDKs you’re going to use. I didn’t know OneSignal existed until I started looking for a free push provider, to replace Urban Airship, because I found it too expensive.

2. Decouple your code
Regardless of how dull it may sound: Model-View-Controller still has a point. We’re getting used to coding Model-View-Whatever, but the principle of MVC remains: your Controller shouldn’t configure Views, and your View shouldn’t manipulate a Model.

Cocoa Touch makes it hard to not use MVVM (Model-View-ViewModel), but that doesn’t mean you should tightly couple your Model code in your View Controller code.

In programming theory we’ve got two principles: coupling and encapsulation. Working with two tightly coupled classes means ClassA makes a lot of assumptions about the inner functionality of ClassB.

Imagine a car and a driver. The driver sits in the front of the car, because the steering column is directly connected to the engine. What if the driver suddenly decided to sit in the back, in order to drive the car? Then the driving doesn’t work. Of course, such a situation never happens in real life, but it happens in your code all the time.

A protection against tight coupling is encapsulation. This means every class has a strictly defined set of methods, such as speedUp() and steerLeft(). Instead of letting the driver inject more gas into the combustion chamber, relying on the engine being of the combustible kind, you simply let the driver call speedUp(). This way the driver doesn’t have intricate knowledge about the workings of the engine, but instead calls upon a function he knows is safe.

When the engine gets replaced by an electric one, which doesn’t have a combustion chamber, you don’t have to change the driver’s code: he relies on a speedUp() method to be present, instead of relying on a injectGasMixture(), gasMixture and sparkTimer.

If you find the principle of decoupling and encapsulation hard to grasp, think of it as responsibilities. Whose responsibility is it to drive the car? The driver’s. Who’s responsibility is it to make the car able to move forward? The engine’s.

When you’re coding your back-end enabled app, make sure you clearly define its components and their responsibilities. Create a class you only use as an intermediary between back-end code and front-end code. The front-end code is based on your own native classes, like Car, and the back-end code has intricate knowledge about the back-end SDK you use, and works with classes like PFObject.

It’s the intermediary’s job to communicate between the front-end and the back-end. In case your back-end code becomes obsolete, you can replace the intermediary with code that understands your new back-end SDK, without rewriting the front-end code as well.

3. Use the Adapter Pattern
The third and last heuristic ties into the principle of loosely coupled code. The Adapter Pattern, older than the internet itself, is an Object-Oriented Programming pattern. It’s a set of programming design rules you can use to make two incompatible classes compatible with each other.

It’s similar to making a “wrapper”, but instead of just exposing the interface of one resource (like wrapping a REST API) it also mediates between two incompatible interfaces by defining a set of rules. In many programming languages these rules are called interfaces (Java and PHP), in Swift and Objective-C they’re called protocols.

You do know Swift’s generics, right? If it swims like a duck and quacks like a duck, it must be a duck. The Adapter Pattern has a similar mechanism. Instead of integrating ClassA and ClassB tightly with each other, by making direct calls from A to B, you build an adaptor class around ClassA.

The adapter class has intricate knowledge about how ClassA works. The adapter class also conforms to a protocol. The protocol says: “You can be sure I have methods X, Y and Z”.

ClassB doesn’t know ClassA. It only knows it wants to work with an instance that conforms to the adapter’s protocol. It doesn’t care if the instance is a duck, as long as it swims and quacks like a duck.

What’s the benefit of working with an adapter? Well, in case your original ClassA code becomes obsolete, you can just find another class (i.e. another Parse alternative) and write an adapter for it. As long as this adapter conforms to the protocol, the rules you defined earlier, ClassB still works.

In reality, you would write an adapter (MyTwitterAdapter) that has a method with this signature:

class MyTwitterAdapter:AnyTwitterServiceProtocol
{
    func getTweetsWithUser(user:User, withPage page:Int = 0)
    {
        ...

The protocol (AnyTwitterServiceProtocol) contains the exact same method signature, but it doesn’t have any logic or method implementation. It just sets the rules.

protocol AnyTwitterServiceProtocol
{
    func getTweetsWithUser(user:User, withPage page:Int = 0);
    ...

The front-end code (MyTweetsViewController) has a variable twitter of an undefined type, which it got from the “adapter factory”. This factory ensures you only have to replace class names once (or twice) if you change adapters.

If you’d strictly define twitter to be of type MyTwitterAdapter, you would still tightly couple your code, most likely in more than one place. Then, if you replace your adapter for a new one, you still have to update a lot of code.

Once you’ve got this set up, you can test if the twitter instance you’re working with conforms to the AnyTwitterServiceProtocol.

if let _twitter = twitter as? AnyTwitterServiceProtocol
{
    // Yes, it conforms
}

Your front-end code doesn’t care anymore whether twitter is of type Car, FooBar or Facebook, as long as it conforms to AnyTwitterServiceProtocol. It simply wants to know if the instance has a method called getTweetsWithUser:withPage:.

Note: in case you do want to strictly define the type of twitter, you can use a protocol as a type, and you can also work with generics.

What’s Next?

Now that you’ve learned that you should improve your business operations and your reliance on suppliers, and protect your code against sudden changes, you can figure out how to do that.

Are you going to switch to Firebase? You should know that Firebase is owned by “Big Five” Google, and although Parse’s shutdown is no harbinger of more shutdowns, solely relying on a new provider leaves you equaly vulnerable as you were. Unless you protect your code, of course.

A good exercise would be to learn about back-end programming. Parse has released an excellent replacement product, Parse Server, which you can run on your own server (as long as it can run NodeJS and MongoDB). In the following code guide I’ll show you how to migrate a simple app from Parse to Parse Server, with Heroku and MongoLab.

Continue: Guide: How To Migrate Your Parse App To Parse Server With Heroku And MongoLab

Another relatively easy exercise is to migrate your Push Notifications to two services instead of one. Implementing the client-side SDK of a push provider is relatively easy, usually you only have to send over the unique push ID and set up a segment.

Use the Adapter Pattern to create a unified interface your front-end code can talk to. Decouple the actual adapter from the front-end code by defining a protocol. Pick a second Push Notifications provider (like Urban Airship, Mixpanel, Pusher or PushOver) and write a second adapter. Make sure it conforms to the protocol, and then simulate a service breakdown in which you have to deploy your new adapter. Does it work?

Conclusion

Don’t be afraid to go deep into the black box. It’s not a bad idea to write your own back-end REST API, just for the fun and experience of it. You’ll learn a lot.

Did you know Crashlytics is owned by Twitter? Anything could shutdown… Make sure you know what Crashlytics does for you, and how it works. It’s the only way to build a stable, reliable and long-term profitable business.

Down the rabbit hole you go.

About the author

Reinder de Vries is an indie app maker who teaches aspiring app developers and marketers how to build their own apps at LearnAppMaking.com. He has developed 50+ apps and his code is used by millions of users all over the globe. When he’s not coding, he enjoys strong espresso and traveling.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Adding IBInspectable to a superclass in Swift

Adding IBInspectable to a UICollectionViewCell subclass

One very useful feature I find is to add a IBInspectable background image to my views. In an entertainment app I’m currently building there is a designable cell that looks like this:

@IBDesignable
class TrailerCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBInspectable weak var bgImage: UIImage! {
        didSet {
            imgView.frame = self.bounds
            self.addSubview(imgView)
            imgView.image = bgImage
            imgView.contentMode  = UIViewContentMode.Center
            self.sendSubviewToBack(imgView)
        }
    }
}

what’s great about this is it gives me a very easy way to set a background image on my TrailerCollectionViewCell. It shows right up in my storyboards so I can easily set it to my “play” icon graphic.

IBInspectable in Xcode 7

Notice on the top-right of the attributes inspector it adds a “Bg Image” dropdown. When this is changed the didSet method above is triggered and it updates the view inside of Xcode, and when the iOS app runs. This is happening because the decoding from interface builder will also trigger didSet in the same fashion that interface builder does.

What’s not so handy about this approach is that I have two other types of CollectionViewCell subclasses that need similar functionality. So, I have these three classes inherit from one superclass that implements the functionality.

import Foundation
import UIKit
 
class MediaCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    var imgView = UIImageView()
    @IBInspectable weak var bgImage: UIImage! {
        didSet {
            imgView.frame = self.bounds
            self.addSubview(imgView)
            imgView.image = bgImage
            imgView.contentMode  = UIViewContentMode.Center
            self.sendSubviewToBack(imgView)
        }
    }
}
 
class TrailerCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
}
 
class ReviewCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var ratingLabel: UILabel!
}
 
class PlaythroughCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBOutlet weak var ratingLabel: UILabel!
}

It doesn’t work!

Here’s the problem though: The field disappears in my storyboard!

I spent some time debugging this issue, and found that I could work around it by overriding the bgImage variable in my subclasses, but it was not neccessary to re-implement anything. Success!

The fix

Just adding this line did the trick:

@IBInspectable override var bgImage: UIImage! { didSet {} }

So now my complete file looks like this:

import Foundation
import UIKit
 
class MediaCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    var imgView = UIImageView()
    @IBInspectable weak var bgImage: UIImage! {
        didSet {
            imgView.frame = self.bounds
            self.addSubview(imgView)
            imgView.image = bgImage
            imgView.contentMode  = UIViewContentMode.Center
            self.sendSubviewToBack(imgView)
        }
    }
}
 
class TrailerCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBInspectable override var bgImage: UIImage! { didSet {} }
}
 
class ReviewCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var ratingLabel: UILabel!
    @IBInspectable override var bgImage: UIImage! { didSet {} }
}
 
class PlaythroughCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBOutlet weak var ratingLabel: UILabel!
    @IBInspectable override var bgImage: UIImage! { didSet {} }
}


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Being Swifty with Collection View and Table View Cells

Here’s a common scenario: You have a table view or collection view that has a variety of different types of content. You want to display varying cells based on these types of content, and they’re all mixed within a single section. Pardon the stand-in art, but it looks roughly like this:

In the Objective-C world, it was typical to just use an NSArray to hold whatever records your collection view was going to be using as a data source, and then for each element check what class it is before picking a cell. This case seems particularly not Swifty these days.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"identifier" forIndexPath:indexPath];
    id record = self.records[indexPath.row];
    if([record isKindOfClass:[PlaythroughItem class]]) {
        // ...
    }
    else if([record isKindOfClass:[ReviewItem class]]) {
        // ...
    }
    else if([record isKindOfClass:[TrailerItem class]]) {
        // ...
    }
    return cell;
}

shudder

Okay so that’s not the most type-safe approach, although it’s surprisingly common in Obj-C iOS code. As a better alternative in Swift, we can use enum cases for the different item types, and perform lookups of the items themeselves as needed. Let’s look at an example.

Example

In an entertainment app I’m working on I’ve got a few types of cells for the types of news items that come in:

enum NewsItem {
  case Trailer(index: Int)
  case Review(index: Int)
  case Playthrough(index: Int)
}

The index is just a way to keep track of which item this it supposed to represent in the database. We take this approach to keep the amount of data needed to produce the collection view down. We don’t need all the associated data with every video to be present when putting together a collection view, we just need the info on what cell is tapped, after it is tapped.

Let’s say we have a simple collection view that shows one of these three and picks a custom cell for each. In a Swift file NewsFeed.swift I have that acts as the dataSource of my collection view for the main news view. Of particular interest is the cellForItemAtIndexPath method, which runs the NewsItem record through a switch and produces the correct type of cell, with the relevant information populated:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let record = records[indexPath.row]
    switch(record) {
    case .Playthrough(let index):
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("PlaythroughCell", forIndexPath: indexPath) as! PlaythroughCollectionViewCell
        let playthrough = MediaDB.playthroughAtIndex(index)
        cell.titleLabel.text = playthrough.title
        cell.lengthLabel.text = playthrough.length.prettyTime
        return cell
    case .Review(let index):
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ReviewCell", forIndexPath: indexPath) as! ReviewCollectionViewCell
        let review = MediaDB.reviewAtIndex(index)
        cell.ratingLabel.text = "\(review.rating) out of 10"
        cell.titleLabel.text = review.title
        return cell
    case .Trailer(let index):
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TrailerCell", forIndexPath: indexPath) as! TrailerCollectionViewCell
        let trailer = MediaDB.trailerAtIndex(index)
        cell.titleLabel.text = trailer.title
        cell.lengthLabel.text = trailer.length.prettyTime
        return cell
    }
}

This code works well enough, record is of type NewsItem which can be one of three cases for the different news items we support:

enum NewsItem {
  case Trailer(index: Int)
  case Review(index: Int)
  case Playthrough(index: Int)
}

The associated index value is so that we can find the individual item in the DB when the collection view wants to display a cell.

Something about this code didn’t sit right with me though. I felt that too much of the code was boilerplate; in particular the switch felt bulky and like it had too much work being done inside each case.

But what if I created a protocol for any data source that could be presented as a collection view cell? It would change on a view-by-view basis so I don’t actually want this in my model.. but I do like having it on these particular CollectionViewCell subclasses.

So, I created a protocol called NewsCellPresentable, which I can adhere to in extensions with my custom collection view cells:

protocol NewsCellPresentable {
    func configureForIndex(index: Int)
}
extension PlaythroughCollectionViewCell: NewsCellPresentable {
    func configureForIndex(index: Int) {
        let playthrough = MediaDB.playthroughAtIndex(index)
        self.titleLabel.text = playthrough.title
        self.lengthLabel.text = playthrough.length.prettyTime
    }
}
extension ReviewCollectionViewCell: NewsCellPresentable {
    func configureForIndex(index: Int) {
        let review = MediaDB.reviewAtIndex(index)
        self.titleLabel.text = review.title
        self.ratingLabel.text = "\(review.rating) out of 10"
    }
}
extension TrailerCollectionViewCell: NewsCellPresentable {
    func configureForIndex(index: Int) {
        let trailer = MediaDB.trailerAtIndex(index)
        self.titleLabel.text = trailer.title
        self.lengthLabel.text = trailer.length.prettyTime
    }
}

This feels much cleaner already. Now I can go back to my cellForItemAtIndexPath method and trim it down to just the following:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let record = records[indexPath.row]
    var cell: NewsCellPresentable
    switch(record) {
    case .Playthrough(let index):
        cell = collectionView.dequeueReusableCellWithReuseIdentifier("PlaythroughCell", forIndexPath: indexPath) as! PlaythroughCollectionViewCell
        cell.configureForIndex(index)
    case .Review(let index):
        cell = collectionView.dequeueReusableCellWithReuseIdentifier("ReviewCell", forIndexPath: indexPath) as! ReviewCollectionViewCell
        cell.configureForIndex(index)
    case .Trailer(let index):
        cell = collectionView.dequeueReusableCellWithReuseIdentifier("TrailerCell", forIndexPath: indexPath) as! TrailerCollectionViewCell
        cell.configureForIndex(index)
    }
    return (cell as! MediaCollectionViewCell)
}

What do you think? Is this a cleaner approach? Let me know if you have a different method in the comment, or let me know on Twitter. My username is @jquave.

P.S.

If you want to try this out yourself and don’t have the same DB layer as me… guess what? Neither do I! You can easily stub this out like this:

class MediaDB {
    class func titleForRecord(index: Int) -> String {
        return "Title!!"
    }
    class func trailerAtIndex(index: Int) -> Trailer {
        return Trailer()
    }
    class func reviewAtIndex(index: Int) -> Review {
        return Review()
    }
    class func playthroughAtIndex(index: Int) -> Playthrough {
        return Playthrough()
    }
}
struct Trailer {
    let title = "Trailer Title"
    let length = 190
}
struct Review {
    let title = "Review Title"
    let rating = 4
}
struct Playthrough {
    let title = "Playthrough Title"
    let length = 9365
}
enum NewsItem {
    case Trailer(index: Int)
    case Review(index: Int)
    case Playthrough(index: Int)
}

Personally I always stub things out with static values before I do the work of integrating with a backend service or whatever data provider is needed. This makes it much easier to iterate.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Swift 2 – What’s new

Monday Apple announced Swift 2, and just about everything announced is an extremely welcome change. This post is a summary of Chris Lattner’s discussion in the WWDC video “What’s new in Swift”. Now, let’s run through them…

Fundamentals

enums can now be printed to the console and show the actually value instead of just (enum value). Additionally, println is now just print. If you have ever used log debugging to figure out a problem involving enum values, rejoice!

I tested this and saw that not only is the enum value is printed, but so is the entire context of when and where the print() function is called.

enums can now support multiple types, so long to Box!

enum<T1, T2> {
  case First(T1)
  case Second(T2)
}

The do keyword:

do {
  //...
} while(someVar<5)

// Can now be represented as:
repeat {
  //...
}

Option Sets can now use a standard Set type in Swift 2.0

viewOptions = .Repeat | .CurveEaseIn
viewOptions = nil

// Can now be represented as a set:

viewOptions = [.Repeat, .CurveEaseIn]
viewOptions = []

We can also create our own set types

(Default implementations in protocols)

struct MyStyle : OptionSetType {
  let rawValue: Int
  static let Bold     = MyStyle(rawValue: 1)
  static let Italic   = MyStyle(rawValue: 2)
}

iStyle.style = []
iStyle.style = [.Bold, .Italic]

if iStyle.style.contains(.Bold) {
  //...
}

Function arguments now behave the same way, regardless of if they are global functions, or methods on a data structure.

So now, you provide arguments labels on functions by default:

func myFunc(name: String, age: Int) { ... }

myFunc("John", age: 35)

The # syntax is now gone, previously used to make the external argument name the same as the internal argument name.

In tests, public and internal are visible, via running a special run mode.

Pattern Matching
Added the guard statement which exits the scope in the else statement.

guard let name = json["name"] as? String else {
  return .Second("missing name")
}

// You can also combine this is to complex guards
guard let name = json["name"] as? String,
      let year = json["year"] as? Int else
    return .Second("bad input")
}
// name and year are now String and Int types, not optionals!
return .First(name, year)

Switch/case can now be used with inline if statements

switch bar() {
case .SomeCase(let value) where value != 42:
  doThing(value)

default: break
}

// Can now be represented as
if case .SomeCase(let value) = bar() where value != 42 {
  doSomething(value)
}

for in loops now support boolean filters and full pattern matching

for value in mySequence where value != "" {
  doThing(value)
}

for case .MyEnumCase(let value) in enumValues {
  doThing(value)
}

BONUS: Example of try-catch for JSON vs invalid JSON

let jsonString = "{\"name\":\"Fred\", \"age\":40}"
let badJsonString = "This really isn't valid JSON at all"

let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
let badJsonData = badJsonString.dataUsingEncoding(NSUTF8StringEncoding)!

do {
    // Try parsing some valid JSON
    let parsed = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments)
    print(parsed)
    
    // Try parsing some invalid JSON
    let otherParsed = try NSJSONSerialization.JSONObjectWithData(badJsonData, options: NSJSONReadingOptions.AllowFragments)
    print(otherParsed)
}
catch let error as NSError {
    // Catch fires here, with an NSErrro being thrown from the JSONObjectWithData method
    print("A JSON parsing error occurred, here are the details:\n \(error)")
}


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Open Source Swift – A Look At The Top Swift Repositories

Github, the most popular open source repository for open source software, offers a feature that let’s us view repositories by language. In this post, I want to dissect some of the most popular Swift repositories as of June 5th, 2015. So, let’s kick it off with the most starred Swift repository, Alamofire.

Alamofire

Alamofire is an “Elegant HTTP Networking in Swift”, written by Matt Thompson, a well known Objective-C developer responsible for the AFNetworking library. The library takes the built-in iOS networking features and abstracts them away in to a simpler, and more Swift-y API.

Take for example the case of a simple GET request that returns JSON:

Alamofire.request(.GET, "http://httpbin.org/get")
         .responseString { (_, _, string, _) in
                  println(string)
         }

It’s the most popular library for Swift to date, so you should probably be using it, right?

Well, maybe… The library makes some common tasks simpler and less verbose, but if you don’t know the basics of networking in Swift (or Objective-C), it’s probably best to get a good understanding of the existing APIs first. After understanding what’s going on under the hood, you can make a more informed decision about whether or not you need the extra layer of abstraction. Alamofire is a big framework, and networking is a huge topic, so I don’t want to get too far in to the details on this library. But, suffice to say if you are working with complex networking requests with lots of back and forth with a web server, and/or working with a complicated authentication process, using Alamofire might reduce some of the repetitive coding tasks. If you are new to iOS development, I would recommend just stick to the APIs provided by Apple for now.

SwiftyJSON

SwiftyJSON is “The better way to deal with JSON data in Swift” according to it’s Github entry. This framework is one of the first I saw when Swift was first released, that combined with the fact that JSON parsing is such a common problem is how it became a top repository, helping to deal with the messiness of Apple’s built-in JSON parser. In particular, the static typing of Swift and optional syntax led to a lot of verbose JSON parsing code, guessing and checking each step of the way for each key and checking every cast. The truth is though, using this library is VERY similar to just using optional chaining and Swift’s normal casting syntax. There is not much benefit here, and from what I’ve seen in production, SwiftyJSON has some performance problems, as a result I’m not sure I would recommend using it right now, except in prototype apps, or during the learning phase.

Take a look at the example they give as the standard approach to parsing JSON, which they describe as “not good”:

let JSONObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil)

if let statusesArray = JSONObject as? [AnyObject],
   let status = statusesArray[0] as? [String: AnyObject],
   let user = status["user"] as? [String: AnyObject],
   let username = user["name"] as? String {
    // Finally we got the username
}

They then present their alternative version of the syntax:

let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string{
  //Now you got your value
}

There’s a few issues here, first of which is that the simplifications they are showing are partially just taking advantage of language features that would actually work with the regular parser. Second, it seems like their example actually would not work.

Based on the example code shown above, the example JSON they are parsing looks something like this:

{
    "statuses": [
        {
            "user": {
                "name": "Bob"
            }
        }
    ]
}

One issue with this sample right off the bat is that they are casting the initial value of the JSON to an array, which would suggest that the root element is an array, which is invalid JSON. The type of the root object in valid JSON is always going to be a key/value. Or equivalently in Swift, a Dictionary of type [String:AnyObject]. Additionally, it’s good practice to actually check if the JSON parsing succeeded or not.

Once we start going through and fixing all the issues with the sample code, assuming we want to explicitly cast everything as they have shown, we end up with something like this:

if let JSONObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [String:AnyObject],
    statusesArray = JSONObject["statuses"] as? [[String:AnyObject]] {
        let status = statusesArray[0] as [String: AnyObject]
        if let user = status["user"] as? [String: AnyObject],
            let username = user["name"] as? String {
                println("username: \(username)")
        }
}
else {
    println("Failed to parse JSON, handle this problem")
}

Now, this is in fact pretty verbose, and could be reduced quite a bit, but let’s stop a think about what we’re doing here. In this example, we are trying to download a list of statuses which are owned by users, and they have names. In an actual Swift application, I would expect there to be a model representing these objects. Maybe something like this:

struct User {
    let name: String
}
struct Status {
    let user: User
}

Assume we are using SwiftyJSON for a moment, how would we add these records to the model of our app? Maybe with a bit of code like this…

struct User {
    let name: String
}
struct Status {
    let user: User
}

let parsedJson = JSON(data: data)
for (key, val) in parsedJson["statuses"] {
    if let username = val["user"]["name"].string {
        let owner = User(name: username)
        let newStatus = Status(user: owner)
    }
}

This works relatively well, assuming we are just creating objects from a JSON feed rather than synchronizing them. But what if there is a server error and the JSON comes back invalid? For example if there is a server error which changes the JSON to present an “error” key, and it no longer includes “statuses”, this loop simply would not be executed. Failing silently is better than crashing, but it would be nice to check for issues and try again, or adjust something in the app.

Since we need to check for the presence of statuses, and this for loop doesn’t actually do that, we need to check the count of statuses first, which means we need to cast it to an array, and *then* check the count…

if(parsedJson["statuses"].count<1) {
    println("Oops! An error occurred")
}

And that's that! Right?
Well, no...

If the key isn't defined, this count property evaluates to 0, which could just mean there is no new statuses to see. The count really should not be zero, it should be null.. but SwiftyJSON is telling us it's 0. This seems like the kind of thing I really *don't* want a JSON parser to be doing. They really seem to not like the optional syntax in Swift, and instead reinvented it with these type properties. Why not just stick with convention?
Our final code might look something like this:

struct User {
    let name: String
}
struct Status {
    let user: User
}

let parsedJson = JSON(data: data)
for (key, val) in parsedJson["statuses"] {
    if let username = val["user"]["name"].string {
        let owner = User(name: username)
        let newStatus = Status(user: owner)
    }
}
if(parsedJson["statuses"].count<1) {
    println("Oops! An error occurred")
}
if let err = parsedJson["error"].string {
    println(err)
}

Our code is starting to grow, and this doesn't cover a ton of things we would need in a real-world application, such as updating the model, including more properties, checking for equality, enforcing uniqueness, cascading relationship changes, and a host of other things. Core Data can handle much of this, and it's common practice to implement models as Core Data models, but that still creates a situation where we have to custom implement all kinds of methods for converting the entire model object (such as Status) *back* in to JSON to update the server.

In the Objective-C world there is Mantle, a great library for handling such things. Before that there was RestKit. RestKit however made some ...interesting... design decisions a few years ago in a big update, and haven't ever really recovered since then. Unfortunately I haven't found a good solution for Swift just yet, and trying to work with Mantle proves to be problematic in it's current form, unless you implement all your models in Obj-C, something I'm not sure we all want to do at this stage.

I know this isn't all problems with SwiftyJSON, but they ironically break a lot of Swift conventions in dealing with optional values. SwiftyJSON is really a terrible name, they are very much not Swifty at all. However, the syntax is a little easier on the eyes. Personally, I don't use the library in my projects.

Spring

Spring is "A library to simplify iOS animations in Swift." How does it do this? Let's take a look.

Trying out some sample code I threw together this quick demo UIViewController that adds a blue square to the screen and animates it in, give it a try yourself, it's pretty nifty:

import UIKit
import Spring

class ViewController: UIViewController {
    var square = SpringView(frame: CGRectMake(0, 0, 200, 200))
    override func viewDidLoad() {
        super.viewDidLoad()
        
        square.center = self.view.center
        square.backgroundColor = UIColor.blueColor()
        square.animation = "squeezeDown"
        square.animate()

        self.view.addSubview(square)
    }
}

The SpringView seems to basically just be a UIView subclass with the animations added in. I don't know if I really like the idea of having to use their UIView, but I suppose most of the time I just use the basic UIView, and even if I didn't, I could just subclass SpringView instead.

Spring sports quite a few animation types, set as a string. The square.animation = "squeezeDown" here is what's determining the animation to play. The library goes beyond this, and in fact allows simple animations to be created in storyboards. So in theory you could put Spring in your Xcode project, and then pass it off to a designer to set up some nifty animations using this library. Very interesting idea, I would like to hear from someone who has tried to do exactly this.

Quick

Quick is "The Swift (and Objective-C) testing framework."

Really? It's THE testing framework? Let's take a look at how Quick works as opposed to XCTest, or expecta.

In XCTest, you might define an assertion that you're testing against like this:

class JSONSwiftTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testContrivedExample() {
        let name = "jameson"
        XCTAssertEqual(name, "jameson", "Name should be \"jameson\"")
    }
}

This is okay, it makes the test basically confirm that name is equal to "jameson". It's simple enough, but there is a common trend/desire among developers to instead express test cases in terms of desired behavior, rather than specifically implementing what the desired behavior causes. Those may sound like the same thing, but take a look at how Quick (due to it's usage of the library Nimble) expresses the same thing like this:

import Quick
import Nimble

class AQuickTest: QuickSpec {
    override func spec() {
        describe("the user") {
            it("has the name 'Jameson'") {
                let name = "Jameson"
                expect(name).to(equal("Jameson"))
            }
        }
    }
}

More than anything else, this framework encourages behavioral tests, which is why this example includes more information about our expectations.

Quick also eases some of the pain of asynchronous testing. In XCTest I personally tend to use XCTestAsync, although Xcode 6 does introduce a way to do this using XCTestExpectation. The basic way that works is you can create an expectation object, and then fulfill it when the async operation is complete. It's not a bad approach.

import Quick
import Nimble

@objc class AsyncExample {
    var longTaskIsDone = false
    var timer: NSTimer?
    func startLongTask() {
        timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "taskIsDone", userInfo: nil, repeats: false)
    }
    func taskIsDone() {
        println("task done")
        longTaskIsDone = true
    }
}

class AQuickTest: QuickSpec {
    override func spec() {
        describe("the user") {
            it("has the name 'Jameson'") {
                let name = "Jameson"
                expect(name).to(equal("Jameson"))
            }
        }
        
        describe("Async Example") {
            describe("its long task") {
                it("should finish in 5 seconds") {
                    let asyncExample = AsyncExample()
                    asyncExample.startLongTask()
                    expect(asyncExample.longTaskIsDone).toEventually(beTruthy(), timeout: 3, pollInterval: 0.4)
                }
            }
        }
        
    }
}

In this example we just create an NSTimer that fires in 2 seconds, as a simulated async example. Then in the Async Example test, we can use the .toEventually() method to wait around and keep checking in to the asyncExample.longTaskIsDone property. This is slightly cleaner in that using expectations, because with this method we don't need to change our code to make sure the test is notified of this variable changing. Having an ongoing timer keep checking is great (just be careful not to have it calling methods with side effects!)

Overall Quick seems pretty interesting, the approach is sure to appeal to those in professional environments, or working with an Agile team where specs change fast.

That's it for this time, if you would like to see any of these libraries covered in greater detail be sure to let me know. You can find me on Twitter.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Swift 1.2 and Xcode 6 Beta 2 – The best update yet

The big news in the Swift community is the release of Swift 1.2, featuring some awesome features. Apple wrote about that a bit here, this was before they released Xcode 6.3 Beta 2, which came out today. But it contains most of the major language changes.

Xcode 6.3 Beta 2

First of all, Xcode itself has changed to allow for more easy to use playgrounds. In particular Apple has added rich text comments, in addition to showing results inline rather than in a separate timeline view. Swift performance was also further improve, and an additional method called zip was introduced for merging Swift sequences together.

zip()

Zip is a method that comes straight out of Haskell which accepts multiple sequences of data, and returns a single tuple “zipping” the two data sets together. For example

let a = [1,2,3]
let b = ["a","b","c"]
let zipped = zip(a, b)

Here the value of zipped would become two sequences in a tuple with types [Int] and [String]. Casting this to an Array makes the significance of this a little more clear:

println(Array(zipped))

[(1, a), (2, b), (3, c)].
As you can see the two sequences are simply “zipped” together. This does beg the question though, what if the sequences are of differing lengths?
For example…

let a = [1,2,3]
let b = ["a","b"]
let zipped = zip(a,b)

In this case, the zipping process will use the shortest sequence’s length as the number of elements to zip, and simply discard the trailing elements on the longer sequence. Giving the output, [(1, a), (2, b)]

This is particularly useful when working with what are effectively infinite sequences. You can limit the list by zipping with a finite sequence:

    let squares = Array(map(1..<10) { $0 * $0 })
    let names = ["one", "two", "three"]
    
    let squareList = zip(names, squares)
    
    println(Array(squareList))

Results in:
[(one, 1), (two, 4), (three, 9)]

So, even though the squares sequence can go on forever, it's made in to a finite list due to the fact that names has only 3 elements.

Goodbye pyramid of doom!

The optional binding sometimes leads to messy code like this:

if let first = user.first {
  if let last = user.last {
    return "\(first) \(last)"
  }
}

But with 1.2, these series of if let statements can be collapsed down to just a comma separated list of optional values, and only a single set of curly braces. The above code will behave exactly the same as this:

if let first = user.first, last = user.last {
  return "\(first) \(last)"
}

Sometimes these chains upon chains of optional binding statements can get out of hand, so this is a very welcome feature. As an additional bonus in Xcode 6.3 Beta 2, we can now also add a single optional binding let clause. For example:

if age > 17 && profile.public,
  let first = user.first,
  last = user.last {
    return "\(first) \(last)"
}

This code will not only perform the optional binding in a more concise way with the variables first and last, but it will only do so if the user is of age and has a public profile available, which are assumed to be boolean values in this example. Contrast that with how we wrote this in older versions:

if (age > 17 && profile.public) {
  if let first = user.first {
    if let last = user.last {
      return "\(first) \(last)"
    }
  }
}

The as! keyword was added

When casting from one type to the other, it's possible that the cast could fail. Previously this was handled with the case of an optional using the as? operator. Consider the scenario below

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
let nameStr = name as String
bio(nameStr, location)

Here we are calling a function that requires a String, but we have name typed as an AnyObject object. Before Swift 1.2 this code would be accepted, but this could actually crash your application if the cast fails. In this case it would never fail, so we can safely do this cast, but the syntax shown above does not clearly demonstrate that this cast is actually dangerous. If name gets changed to something that is not castable to a String later, this code would cause the app to crash. In order to more clearly communicate this, the as operator must now become as! if the cast could possibly fail. So the above would now become this:

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
let nameStr = name as! String
bio(nameStr, location)

This helps drive home an important message: If you are using an exclamation mark (!), then you may be setting up a situation where the app could crash due to a failed cast, or null value. As a general rule, you should just never use forced casts unless you absolutely have to (or if you're writing code that won't go in to production)

Keep in mind the as? keyword is unchanged, and in general you should prefer using it in addition to an optional binding for this type of scenario, as this is much safer, e.g.

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
if let nameStr = name as? String {
  bio(nameStr, location)
}

Xcode and Compiler Improvements
This is probably the biggest one for me. The compiler is faster due to incremental builds, and Xcode doesn't crash all the time due to some stability improvements. This alone makes the beta work the download and I highly recommend getting a copy on iOS Dev Center.

Want to learn more about Swift 1.2? Try out some of my free tutorials. My Core Data tutorial was updated recently for 1.2, which I would recommend to anyone interested in working on real iOS Apps.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Core Data Migrations Swift Tutorial

In this post we’re going to discuss migrations in Core Data.

This is part three of a tutorial series covering the usage of Core Data in Swift to write iOS apps with persistence. While I think you can benefit strictly from reading this post, it may be easier to follow along if you go back and read Core Data in Swift Tutorial (Part 1) first.

This post compatible with Xcode 6.3 Beta, Updated on February 16, 2015

At this point in the tutorial, we’ve created a simple app that can create and delete log item’s backed by a Core Data store. We’ve learned about creating, deleting, and modifying Core Data objects. We looked at sorting lists of objects, filtering them out using predicates, and even combined predicates to make compound predicates. With this much information, we can do a ton of stuff with our apps.

Why Make Core Data Migrations?

However there is a problem. Core Data expects a consistent schema. Meaning that if we add or remove entities, attributes, or change their types, it will cause a conflict. This means that if you:
1) Store some data inside of an app using a set schema. For example a Model named LogItem with a title(String) attribute.
2) Change any of the schema. For example add a new full title attribute to become ‘fullTitle’.
3) Run the app again

There will be a conflict, and the app will do a hard crash. This includes anyone who has downloaded your app from the app store! Not only that, if you change the text attribute, and you don’t perform any kind of migration, you will be risking losing user’s data. If you want people to uninstall your app, this is a *fantastic* way to make that happen. If not, keep reading 🙂

Causing a migration failure

To demonstrate the default behavior, it’s useful to see what happens if we don’t take care to perform migrations. If you’ve been following along you should have a Core Data model that contains one entity, LogItem with two String attributes, itemText and title, as shown in the figure below.

Core Data Model For Migrations

Core Data Model For Migrations

First off, we need to run our app and create some records. If you’ve been following along you can just add a few log items. This is enough to populate the Core Data store, and create a set schema.

Next, let’s add our “fullTitle” String attribute. Just click the “Add Attribute” button and punch in fullTitle as the name, and String as the type.

Now, run the app again, what do you find? Well, you get a rather massive looking confusing error in the console:

CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///Users/USERNAME/Library/Developer/CoreSimulator/Devices/70F453BF-0E8E-4916-8B1F-1D3FDAC9AAE3/data/Containers/Data/Application/90912396-CB66-4B4A-8502-BDE916F6243D/Documents/MyLog.sqlite options:(null) ... returned error Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)" UserInfo=0x7ffd126842c0 {metadata={
    NSPersistenceFrameworkVersion = 519;
    NSStoreModelVersionHashes =     {
        LogItem = <3954a6a4 f606a77c d84981b4 c8ec4869 5eda2e90 4c7e0069 b090d4b8 825d8ee3>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
        ""
    );
    NSStoreType = SQLite;
    NSStoreUUID = "";
    "_NSAutoVacuumLevel" = 2;
}, reason=The model used to open the store is incompatible with the one used to create the store} with userInfo dictionary {
    metadata =     {
        NSPersistenceFrameworkVersion = 519;
        NSStoreModelVersionHashes =         {
            LogItem = <3954a6a4 f606a77c d84981b4 c8ec4869 5eda2e90 4c7e0069 b090d4b8 825d8ee3>;
        };
        NSStoreModelVersionHashesVersion = 3;
        NSStoreModelVersionIdentifiers =         (
            ""
        );
        NSStoreType = SQLite;
        NSStoreUUID = "";
        "_NSAutoVacuumLevel" = 2;
    };
    reason = "The model used to open the store is incompatible with the one used to create the store";
}
2014-12-15 14:00:36.135 MyLog[67495:21018487] Unresolved error Optional(Error Domain=YOUR_ERROR_DOMAIN Code=9999 "Failed to initialize the application's saved data" UserInfo=0x7ffd13b26970 {NSLocalizedDescription=Failed to initialize the application's saved data, NSLocalizedFailureReason=There was an error creating or loading the application's saved data., NSUnderlyingError=0x7ffd12684300 "The operation couldn’t be completed. (Cocoa error 134100.)"}), Optional([NSLocalizedDescription: Failed to initialize the application's saved data, NSLocalizedFailureReason: There was an error creating or loading the application's saved data., NSUnderlyingError: Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)" UserInfo=0x7ffd126842c0 {metadata={
    NSPersistenceFrameworkVersion = 519;
    NSStoreModelVersionHashes =     {
        LogItem = <3954a6a4 f606a77c d84981b4 c8ec4869 5eda2e90 4c7e0069 b090d4b8 825d8ee3>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
        ""
    );
    NSStoreType = SQLite;
    NSStoreUUID = "";
    "_NSAutoVacuumLevel" = 2;
}, reason=The model used to open the store is incompatible with the one used to create the store}])

This is a rather intimidating error message. There’s so much to read, and so little of it is familiar. I want you to focus on on particular key though, “reason”.
When you get a Core Data error, it comes back with a ton of information, and the relevant part is almost always the value of “reason”. In our error, we see a couple of reasons, but we’re most interested in the very first one.

reason=The model used to open the store is incompatible with the one used to create the store} with userInfo dictionary

The error pretty much says what I described earlier. We changed the schema, and Core Data doesn’t like it. Let’s change the schema back by removing fullTitle, and set up a migration instead. (Run your app again to make sure it still works!)
If you find you have a conflicted Core Data model, but you don’t want to create a migration yet, you can also just delete the app from your simulator or device. This will create the new schema instead. This is generally my solution when my model is going through a lot of migrations, but you NEVER want to do this with a deployed model version. You’ll just have people on the app store with your app crashing. They aren’t going to know to delete the app and reinstall either, they’ll just delete it and leave you a 1-star review.

Create A Migration

To create a migration, we need to first make some changes to our persistent store. This is the code that Xcode generates for us when we create a project using an Xcode template. By default, Xcode does not include any kind of migration options at all.

In the code that Xcode provides there is a lazily computed variable called persistentStoreCoordinator, and it’s responsible for making migrations happens. It looks like this, and we’re most interested in line 8.

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("MyLog.sqlite")
    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."
    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
        coordinator = nil
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason
        dict[NSUnderlyingErrorKey] = error
        error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog("Unresolved error \(error), \(error!.userInfo)")
        abort()
    }
    
    return coordinator
}()

Now, the persistent store coordinator is being added using the addPersistentStoreWithType method. This method looks like it is maybe not updated for Swift, but that’s okay, we just need to pay attention to what’s optional and what’s not. Let’s take a look at the documentation, click here to open in a new window.

Opening up these docs you can see some details on what these parameters are. In particular it describes “options”.

Apple Documentation For Core Data

Apple Documentation For Core Data

You’ll notice in the parameters table, the “options” parameter is a dictionary. It also has a link to a particular set of parameters you could use in the dictionary, “Migrations Options”. Clicking on that will bring you to the constants the iOS SDK has prepared for us already:

Migration options, specified in the dictionary of options when adding a persistent store using addPersistentStoreWithType:configuration:URL:options:error:.

Declaration
SWIFT
let NSIgnorePersistentStoreVersioningOption: NSString!
let NSMigratePersistentStoresAutomaticallyOption: NSString!
let NSInferMappingModelAutomaticallyOption: NSString!
Constants
NSIgnorePersistentStoreVersioningOption

Source: Apple.com

NSMigratePersistentStoresAutomaticallyOption sounds pretty nice. Automatic migration? Sign me up! NSInferMappingModelAutomaticallyOption will create the mapping model, while NSMigratePersistentStoresAutomaticallyOption will perform the migration.

So, to set this up, we just have to create a dictionary with these keys set, and pass that in as the options parameter of addPersistentStoreWithType

So let’s create the dictionary:

let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
        NSInferMappingModelAutomaticallyOption: true]

And pass it in to the options parameter:

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("MyLog.sqlite")
    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."
    let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
        NSInferMappingModelAutomaticallyOption: true]
    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions, error: &error) == nil {
        coordinator = nil
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason
        dict[NSUnderlyingErrorKey] = error
        error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog("Unresolved error \(error), \(error!.userInfo)")
        abort()
    }
    
    return coordinator
}()

So basically what we just did, is we specified we would like Core Data to try and automatically merge and map our models between versions.

If you think about what we actually changed in our model, it’s strange that it causes a hard crash. We weren’t using the fullTitle attribute anywhere, it’s just a new field to add really. It could just be automatically added to every model with a null value. Or, if we specified a default value for the attribute, it could just apply that to all existing records. That would be much better than crashing, but Xcode doesn’t want to just make the assumption that we want to do that. So this is how we specify we want Xcode to try anyway.

Now, let’s actually add the new attribute. Before, we just opened up our model and added it as a new String attribute, but that’s not going to create a migration model. We need two versions of the model so that Core Data can understand the differences in the two models.

Add a Model Version

In the Project Navigator, select your Core Data model, for example MyLog.xcdatamodeld. Now in your menu bar, select Editor > Add Model Version.. as shown in the figure below.

Adding a Model Version in Xcode

Adding a Model Version in Xcode

You can call it whatever you want, I’ll be calling it MyLogV2, and press Finish.

You’ll now find you can expand your xcdatamodel file to see multiple versions. Select your second version as shown in the figure below.

Multiple Versions of a Core Data Model

Multiple Versions of a Core Data Model

Now, in our version 2 of the model, let’s add our fullTitle(String) attribute.

We’ll also want to update LogItem.swift, the NSManagedObject subclass we created to represent this model.

If you followed along in the earlier tutorials you should have something like this:

import Foundation
import CoreData

class LogItem: NSManagedObject {

    @NSManaged var itemText: String
    @NSManaged var title: String
    
    class func createInManagedObjectContext(moc: NSManagedObjectContext, title: String, text: String) -> LogItem {
        let newItem = NSEntityDescription.insertNewObjectForEntityForName("LogItem", inManagedObjectContext: moc) as LogItem
        newItem.title = title
        newItem.itemText = text
        
        return newItem
    }

}

We’re missing our new fullTitle attribute, both as a property and in the createInManagedObjectContext initializer. Let’s add it…

import Foundation
import CoreData

class LogItem: NSManagedObject {

    @NSManaged var itemText: String
    @NSManaged var title: String
    @NSManaged var fullTitle: String
    
    class func createInManagedObjectContext(moc: NSManagedObjectContext, title: String, fullTitle: String, text: String) -> LogItem {
        let newItem = NSEntityDescription.insertNewObjectForEntityForName("LogItem", inManagedObjectContext: moc) as LogItem
        newItem.title = title
        newItem.itemText = text
        newItem.fullTitle = fullTitle
        
        return newItem
    }

}

Finally, we need to actually make version 2 of our model active.

Click on the MyLog.xcdatamodeld parent object in the Project Navigator. Then open the Utilities panel on the right-hand side of Xcode, and select the first tab, the File Inspector.

Here under “Model Version” there is a dropdown where you can select the new version 2 of the model, as shown in the figure below.

Changing the Core Data Model Version in Xcode

Changing the Core Data Model Version in Xcode

Now, if you’ve been following along, there are some errors you’ll need to fix where we are initializing the LogItem objects without specifying the fullTitle. We added the attribute to the initializer, so now we need to go one by one and specify the fullTitle in each of these cases.

In particular we need to add these in viewDidLoad where we create some starter objects.

// Loop through, creating items
for (itemTitle, itemText) in items {
    // Create an individual item
    LogItem.createInManagedObjectContext(moc, title: itemTitle, fullTitle: "\(itemTitle) \(itemText)", text: itemText)
}

In earlier tutorials, we also created a saveNewItem function that uses the initializer inside of ViewController.swift. So we need to specify a full title for that as well. For now, we’ll just use a static string “My Full Title” as the fullTitle value.

func saveNewItem(title : String) {
    // Create the new  log item
    var newLogItem = LogItem.createInManagedObjectContext(self.managedObjectContext!,
        title: title,
        fullTitle: "My Full Title",
        text: "")
    
    // Update the array containing the table view row data
    self.fetchLog()
    
    // Animate in the new row
    // Use Swift's find() function to figure out the index of the newLogItem
    // after it's been added and sorted in our logItems array
    if let newItemIndex = find(logItems, newLogItem) {
        // Create an NSIndexPath from the newItemIndex
        let newLogItemIndexPath = NSIndexPath(forRow: newItemIndex, inSection: 0)
        // Animate in the insertion of this row
        logTableView.insertRowsAtIndexPaths([ newLogItemIndexPath ], withRowAnimation: .Automatic)
        save()
    }
}

Now, for the moment of truth… run the app. If you get an error here, let us know on the forums. I know this is a difficult topic, and I know the tutorial is never going to be easy to follow. But, I know if you’ve come this far you can and will succeed in learning this material. We just need to make sure you don’t get stuck.

Otherwise, congratulations, you’ve created your first auto-migration! This is known as a light-weight migration. There is more to migrations than this, as you can specify custom mappings, and there are caveats once you have more than 2 versions of a model. But knowing what we discussed in this tutorial is good enough to get your app to v2.0, and published.

Full source code for this tutorial here: Core Data In Swift Tutorial Code.

Liked this tutorial? It is a modified version of a draft chapter in my Swift Book.

P.S. Wanna write for this site? I need help writing quality content. Learn More Here.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS

Core Data in Swift Tutorial (Part 3)

This post compatible with Xcode 6.3 Beta, Updated on February 16, 2014

This is part three of a tutorial series covering the usage of Core Data in Swift to write iOS apps with persistence. If you haven’t read part one yet, read that first.

If you really want to get your feet wet, my Swift book which is now available for pre-order with early access.


In this (somewhat lengthy) section of the tutorial, we’ll implement deleting rows, adding rows, and persisting the data so it stays put even after app close. When we’re done we’ll have something that works like the video here:

Implementing swipe-to-delete

Before we get started, let’s go ahead and wipe out the filtering we were toying around with in fetchLog(). We’ll just simplify fetchLog to look like this:

func fetchLog() {
    let fetchRequest = NSFetchRequest(entityName: "LogItem")
    
    // Create a sort descriptor object that sorts on the "title"
    // property of the Core Data object
    let sortDescriptor = NSSortDescriptor(key: "title", ascending: true)
    
    // Set the list of sort descriptors in the fetch request,
    // so it includes the sort descriptor
    fetchRequest.sortDescriptors = [sortDescriptor]
    
    if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [LogItem] {
        logItems = fetchResults
    }
}

First, we just need to implement the canEditRowAtIndexPath callback from the UITableViewDataSource protocol. In our case, we’ll be able to delete anything, so we can just return true all the time. But, if for example we had some entries locked, we could check the indexPath and return false instead.

func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

Now, this tells the UITableView that we can edit these rows (deleting a row is a form of editing it.) But iOS will look for one more callback, tableView:commitEditingStyle:forRowAtIndexPath.

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if(editingStyle == .Delete ) {
        // Find the LogItem object the user is trying to delete
        let logItemToDelete = logItems[indexPath.row]
        
        // Delete it from the managedObjectContext
        managedObjectContext?.deleteObject(logItemToDelete)
        
        // Refresh the table view to indicate that it's deleted
        self.fetchLog()
        
        // Tell the table view to animate out that row
        logTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
    }
}

This method gets called on the UITableViewDataSource as well, and it’s called upon performing the swipe-to-delete action on iOS. Without this method implemented swipe-to-delete will simply be disabled.

So, we add it in here and we take action based on the deleted row. When the editingStyle is .Delete, we know that the intention is the delete the row. We identify the row data from our logItems array by accessing the indexPath.row index (this is the integer row number of the deleted item in the table view)

Next, we delete the object in Core Data using the deleteObject method on the managedObjectContext we computed earlier.

Now, we can update the table view itself by calling self.fetchLog() again. We could stop here and called reloadData() on the tableview, but instead we can use the deleteRowsAtIndexPaths:withRowAnimation: method of the table view to get some free table view animations.

Try running the app now, and you can swipe left on a table view row to delete it. You’ll get some free animations, and this data is updated in our Core Data object graph.

Being able to delete objects is great, but we also need to be able to add items if this is going to be a real app. Let’s make an adjustment to our viewDidLoad() code.

We have a line in our code right now setting the height of the tableview:

// Reduce the total height by 20 points
viewFrame.size.height -= 20

If we’re going to add a button we’ll just to adjust this even further, by the amount of the button height, and create the button. So we’ll set that up now:

// Add in the "+" button at the bottom
let addButton = UIButton(frame: CGRectMake(0, UIScreen.mainScreen().bounds.size.height - 44, UIScreen.mainScreen().bounds.size.width, 44))
addButton.setTitle("+", forState: .Normal)
addButton.backgroundColor = UIColor(red: 0.5, green: 0.9, blue: 0.5, alpha: 1.0)
addButton.addTarget(self, action: "addNewItem", forControlEvents: .TouchUpInside)
self.view.addSubview(addButton)

// Reduce the total height by 20 points for the status bar, and 44 points for the bottom button
viewFrame.size.height -= (20 + addButton.frame.size.height)

First, we create a UIButton instance, and set it’s size to be equal to 44×44 points. The position will be at an x coordinate of 0, and a y coordinate of whatever the screen height is, minus the size of the button (44 points) This puts it at the bottom of the screen.
We set the title to simply “+” to indicate adding a new item, set the background color, and add a target.

The target is a selector that fires when the button is clicked. In our case, the selector is called “addNewItem”, which means we need to create this as a function…

let addItemAlertViewTag = 0
let addItemTextAlertViewTag = 1
func addNewItem() {
    
    var titlePrompt = UIAlertController(title: "Enter Title",
        message: "Enter Text",
        preferredStyle: .Alert)
    
    var titleTextField: UITextField?
    titlePrompt.addTextFieldWithConfigurationHandler {
        (textField) -> Void in
        titleTextField = textField
        textField.placeholder = "Title"
    }
    
    titlePrompt.addAction(UIAlertAction(title: "Ok",
        style: .Default,
        handler: { (action) -> Void in
        if let textField = titleTextField {
            println(textField.text)
        }
    }))
    
    self.presentViewController(titlePrompt,
        animated: true,
        completion: nil)
}

This function will create a UIAlertController object with a text field by using the addTextFieldWithConfigurationHandler method. I’ll probably go over this as a separate blog post at some point, but for now it’s enough to know that when the handler on the “Ok” action gets called, the textField’s text value is inside of textField.text. We can use this to take input from the user without adding too much more view work.

Okay, so now that we can detect the text entered, we can call a function to save the new item. We’ll call it saveNewItem:title

func saveNewItem(title : String) {
    // Create the new  log item
    var newLogItem = LogItem.createInManagedObjectContext(self.managedObjectContext!, title: title, text: "")
    
    // Update the array containing the table view row data
    self.fetchLog()
    
    // Animate in the new row
    // Use Swift's find() function to figure out the index of the newLogItem
    // after it's been added and sorted in our logItems array
    if let newItemIndex = find(logItems, newLogItem) {
        // Create an NSIndexPath from the newItemIndex
        let newLogItemIndexPath = NSIndexPath(forRow: newItemIndex, inSection: 0)
        // Animate in the insertion of this row
        logTableView.insertRowsAtIndexPaths([ newLogItemIndexPath ], withRowAnimation: .Automatic)
    }
}

Our method will take in the title as the only argument, and use the createInManagedObjectContext function we created earlier to add a new record with the title of title. For now, we can leave the text blank.

Similar to how we did before with the deletion, we need to call fetchLog() to update our table view’s backing array, logItems.

Finally, we can create our NSIndexPath for the new item, and called insertRowsAtIndexPaths to animate in the new row.

Now, we just need to call the new method from the handler closure in the titlePrompt’s “Ok” button:

titlePrompt.addAction(UIAlertAction(title: "Ok",
    style: .Default,
    handler: { (action) -> Void in
    if let textField = titleTextField {
        self.saveNewItem(textField.text)
    }
}))

Running the app you can now add and delete rows to our table, backed by Core Data. If you close the app and restart it, you may notice that the data is reset every time. This is happening because Core Data doesn’t persist automatically, you must explicitly call save for that behavior. So as a final step in this tutorial section, let’s create a save() method in our ViewController.swift file.

func save() {
    var error : NSError?
    if(managedObjectContext!.save(&error) ) {
        println(error?.localizedDescription)
    }
}

The API is pretty simple just call save() on the managedObjectContext. Optionally you can include an NSError pointer to capture errors. The save() function returns true on success, and false on failure. If the save succeeds, your data will now persist.

Let’s call our save() method after the user adds or removes an item.

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
...
    // Tell the table view to animate out that row
     logTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
     save()
...
func saveNewItem(title : String) {
...
    if let newItemIndex = find(logItems, newLogItem) {
        // Create an NSIndexPath from the newItemIndex
        let newLogItemIndexPath = NSIndexPath(forRow: newItemIndex, inSection: 0)
        // Animate in the insertion of this row
        logTableView.insertRowsAtIndexPaths([ newLogItemIndexPath ], withRowAnimation: .Automatic)
        save()
...
}

Running the app we now have a super nifty app where we can add or remove items from a list with neat animations!

This concludes part 3 of the Core Data tutorial for now. The full source code can be found here.

In the next section, we’ll set up migrations so you can make changes to the schema of your live apps. Core Data Migrations Tutorial in Swift ».

As always, be sure to subscribe to my newsletter for tutorial updates and more, and take a look at my upcoming book, which is now in early access.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.

Subscribe via RSS