Streamlining lots of View Controller interactions with Swift enums.

What ‘problem’ am I trying to solve?

In most cases a View Controller shows one screen to a user, but the user can interact with the screen in multiple ways. Every one of these interactions is handled differently in code. This can be through delegation, target-action, notifications, callbacks, …

For example, take the Travelplanner screen of the Reisplanner Extra app I’m working on.

Overview actions on TravelPlanner screen

  1. A modal Location Picker is presented when the row is pressed
  2. From & To locations are switched when pressed
  3. A modal Location Picker is presented when the row is pressed
  4. A modal Date Picker is presented when the row is pressed
  5. The Now toggle button can be in an on/off/automatic state and changes the behavior of the time row
  6. A modal Travel Options screen is presented when the button is pressed
  7. 8. 9. 10. … more actions 🙂

As you can see, there are a lot of interactions (and there are actually even more interactions for different states of this screen), and all of these interactions need to be handled in code.

In most cases you’ll end up with all kinds of different methods handling these cases, but over time it can start to become unclear where to look when something needs to be changed or added inside your View Controller.

When a (new) team member has to work in the codebase that he has never touched before, it can take some time to find his/her way and know where to look. So how do I try to streamline this?

Swift Enums, your best friend.

Every interaction on the screen, triggers something, and I model all these interactions in a Swift enum called PerformAction .

The enum for the TravelPlanner screen looks like this:

enum PerformAction {
    
    case fromLocationRowPressed( location:Location? )
    case toLocationRowPressed( location:Location? )
    case switchLocationButtonPressed
    case departureArrivalRowPressed( queryType:TravelTimeQueryType, date:Date )
    case nowButtonPressed
    case travelOptionsButtonPressed
    case widgetDirectTo_optionsButtonPressed
    case widgetDirectTo_configureAddressButtonPressed
    case widgetDirectTo_selectLocation( location:Location )
    case widgetCiCo_optionsButtonPressed
    case nothing
    
}

Implementation

This enum is added as a nested type inside the TravelPlannerViewController, so you can reuse the same PerformAction enum name across your files without getting name collisions.

class TravelPlanneViewController: UIViewController {

    enum PerformAction { ... }
    
}

If a new member starts reading through your codebase, he/she can check this enum and see at a glance what all the different actions are for this screen.

To react on these interactions, we create a property performedActionand add a didSet property observer.

var actionPerformed:PerformAction = .nothing {

    didSet {
        
        switch actionPerformed {
            
        case .fromLocationRowPressed( let location ):
            presentLocationPicker( location: location )
        case .toLocationRowPressed( let location ):
            presentLocationPicker( location: location )
        case .switchLocationButtonPressed:
            switchLocations()
        case .departureArrivalRowPressed( let queryType, let date ):
            presentDatePicker( queryType, date: date )
        
        ...
            
        }
        
    }

}

Proxying

Now you have 1 point of entry to handle all your interactions and call your methods.

@IBAction func fromLocationPressed( _ sender: UIButton ) {
    
  actionPerformed = .fromLocationRowPressed( location: fromLocationRow.location )
    
}

@IBAction func switchButtonPressed( _ sender: UIButton ) {
    
  actionPerformed = .switchLocationButtonPressed
    
}

When using RxSwift I use a PublishSubject to keep track of changes.

// Create the subject to keep track of the performed actions
private let performedActionSubject = PublishSubject<PerformedAction>()
    
// Add a new action to the stream
performActionSubject.onNext( .travelOptionsButtonPressed )
    
// Get updates when an action has been performed
viewModel.outputs.actionPerformedObservable.subscribe(onNext: { [weak self] (performedAction) in
    
    switch performedAction {
    
        case ...
    
    }

}).disposed( by: disposeBag )

Final thoughts

This is not a technique I use for a screen with only one or two actions. I tend to model it like this, if there are a lot of interactions.

The downside is you’ll get a bit of extra code, because you proxy your interaction handling to the PerformAction enum.

The benefits are

  1. See all the interactions in the enum at a glance
  2. Clarity of having one point where all the interactions are handled

For newcomers (or your future-you) it will be easier to get around the code.


If you enjoyed this post, follow me on Twitter @thenerd_be 

Integrate Unity 5 in a native iOS app with Xcode 7

Integrate Unity 5 in a native iOS app

A few months back I published a blog post about how to integrate Unity3D within a native iOS application.  This tutorial was written for Xcode 6 & Unity 4 and in the comments there were a lot of requests for a new tutorial.

Tonight I found the time to make the video tutorial on how to integrate Unity 5 in a native iOS app with Xcode 7, so I hope you enjoy it!

Continue reading Integrate Unity 5 in a native iOS app with Xcode 7

3D touch peek and pop tutorial for your Swift application

3D Touch peek and pop tutorial

Apple added a touch-sensitive layer to the screen of the brand new iPhone 6s (plus).  With the coming of this new screen, they’ve added some new UI interactions like application shortcuts and peek and pop.

In this 3D touch peek and pop tutorial I will learn you how to implement this new way of interacting with your content by building a photo gallery.  When you press hard on the screen you’ll see a preview of the image and if you press really hard the preview will pop into a detail view.

At the end of this tutorial I’ll show you how to add preview actions. This way you can interact with the content without going to the detail view.  You can do this by swiping up while you are previewing the content.

Continue reading 3D touch peek and pop tutorial for your Swift application

TouchID authentication tutorial for Swift

TouchID

A few years ago Apple introduced TouchID on the iPhone5S. Instead of asking your user for a password, you can just ask for their fingerprint (if their device has TouchID) which improves the UX by a gazillion times.

With the introduction of iOS7, it was impossible for a developer to use the fingerprint sensor for authentication. Luckily in iOS8, Apple provided us with an API to do so.

In this tutorial I’ll show you how you can integrate TouchID authentication in your application.

Continue reading TouchID authentication tutorial for Swift

Add 3D Touch quick actions tutorial

3d touch quick actions tutorial

With the introduction of the iPhone 6S (plus), Apple added a pressure-sensitive layer to their screen.  This creates a bunch of new UX possibilities for creating apps.  It’s possible to do a hard press on an application icon and get shortcuts which take you to a specific point in your app.  For example, if you do a hard-press on the Photo’s app icon you can quickly search for an image, check the most recent images or see your favourites.  It’s also possible to make these quick actions dynamic, meaning that you can add and remove actions based on the state of your application.

3D touch quick actions
3D touch quick actions

In this tutorial I will show you how you can add these quick actions to your application icon.

Continue reading Add 3D Touch quick actions tutorial

A better way to integrate Unity3D within a native iOS app

Update: I’ve created a new tutorial for Xcode 7 & Unity 5.

Last year I published a blog post about how to integrate Unity3D within a native iOS application.

Last week I found a better way to integrate Unity3D within a native iOS app, which also eliminates some issues with my previous version.  Because it’s quite a long explanation to do and I noticed in my previous blog post that not everything was crystal clear, I’ve made a video tutorial how you can achieve this.

Continue reading A better way to integrate Unity3D within a native iOS app

Load assets from bundle resources in Cocoapods

The problem

Yesterday I stumbled upon a problem when I loaded a xib file within my development pod.

I checked StackOverflow and found a few threads with the same issue:

Continue reading Load assets from bundle resources in Cocoapods

Dynamically load Collada files in SceneKit at runtime

The problem

For an upcoming project, a client asked me if I could build a prototype which could load Collada files at runtime.  The flow has to be like this

  • User downloads Collada zip file while using the app (e.g. in-app purchase)
  • Collada file gets unzipped
  • Show the downloaded Collada file in the app

I started looking a possible 3D engines which I could use like Unity, but then I remembered Apple has released the SceneKit SDK which allows pretty high-level access, but with excellent performance.

Continue reading Dynamically load Collada files in SceneKit at runtime

Create a bootable USB drive for OSX 10.10 Yosemite

Everytime when Apple releases new software, I can’t help it to format my computer. I just don’t seem to trust an update of a operating system. I like to create a bootable USB drive because it’s blazing fast to install an OS. For Yosemite, it took me +- 15 minutes with a USB3 stick.

Luckily it is fairly easy to create a bootable USB drive for OSX 10.10 Yosemite!

Continue reading Create a bootable USB drive for OSX 10.10 Yosemite

Sandbox Unity app in an existing iOS app

I HAVE CREATED A NEW WAY TO INTEGRATE UNITY WITHIN AN EXISTING IOS APP. YOU CAN FIND THE POST HERE.

The problem

After my previous blog post on how to sandbox an iOS app inside of a Unity project, I got some questions on how to do the same but put Unity inside of an existing iOS app.

After playing around with it, I found a solution which works well for me to add Unity app in an existing iOS app.

Continue reading Sandbox Unity app in an existing iOS app