Adventures in iOS Development
Unit Testing and Clean Code Exploration Toolbox Archive About Feed

Making Forms Coding A Little More Fun with View Models, Unit Testing, and Enumerations with Associated Values

Enumerations have much more power in Swift than in C. For one they are not restricted to integer type, e.g. they can be created with “raw” String value and still be matched in switch expression. They can even contain associated values! Canonical example here is Result, used for error handling.

enum Result<T, Error: ErrorType> {
    case OK(T)
    case Error(Error)
}

Let’s look further than that. Associated value data can be of any type: struct, class, enum or even closure. This opens great possibility for passing around configurations with enum cases.

When we have an app with lots of input forms, implementing them gets tedious very quickly. We really want to streamline the process. There are a bunch of libraries dealing with this. However, such big universal solutions come with a cost. It includes time spent familiarizing with framework’s intricacies, running into limitations and working around them. Along the way some needed feature may just not be there. Fork time. All of this can be more effort than building solution that matches our specific needs. Tradeoffs, right?

As an alternative, below is a set of simple guidelines that work both for dealing with static and dynamic collections of items. To keep example brief, it deals only with a few cell types: one for text input, one for selection from group of options, and one for boolean values.

Read more

Custom Error Assertions in Swift

Swift 2 introduced revamped error handling 1. Unfortunately XCTest framework has not been updated for this occasion. Without any custom libraries developers are stuck with tests like those:

func test_throwOnUnkown_UnknownPassed_ThrowsAnyError() {
    do {
        try Movie().throwOnUnkown(.Unkown)
        XCTFail()
    } catch {
    }
}

func test_throwOnUnkown_UnknownPassed_ThrowsTestError() {
    do {
        try Movie().throwOnUnkown(.Unkown)
        XCTFail()
    } catch {
        guard let _ = error as? TestError else {
            return XCTFail()
        }
    }
}

func test_throwOnUnkown_UnknownPassed_ThrowsIllegalArgument() {
    do {
        try Movie().throwOnUnkown(.Unkown)
        XCTFail()
    } catch {
        guard let error = error as? TestError else {
            return XCTFail()
        }
        XCTAssertEqual(TestError.IllegalArgument, error)
    }
}

Example is very rudimentary, however those tests still read badly. Wouldn’t this alternative be much nicer?

func test_throwOnUnkown_UnknownPassed_ThrowsAnyError() {
    let movie = Movie()
    AssertThrows(try movie.throwOnUnkown(.Unkown))
}

func test_throwOnUnkown_UnknownPassed_ThrowsTestError() {
    let movie = Movie()
    AssertThrows(TestError.self, try movie.throwOnUnkown(.Unkown))
}

func test_throwOnUnkown_UnknownPassed_ThrowsIllegalArgument() {
    let movie = Movie()
    AssertThrows(TestError.IllegalArgument, try movie.throwOnUnkown(.Unkown))
}

So how to get rid of unwieldy tests from first example and arrive at second solution?

Read more

ARAnalytics: analytics, clean code and better crash logs

The original post is published on the Tivix blog at the following URL: http://www.tivix.com/blog/aranalytics-analytics-clean-code-crash-logs-on-ios/

Tracking how users are using your app is a must. When looking for improvements we should rely on data, instead on just a hunch. There are a lot of analytics services and each of them has its own SDK. Integrating different analytics services, adding code for logging events and screen views, is at best tedious and bloats code in places that are already susceptible to it (Hello, Massive View Controllers). Switching to another service leads to changing code all over the app. By default it’s also impossible to just quickly try out a new provider, without repeating work that’s already been done.

But it’s not all doom and gloom! ARAnalytics is an Objective-C library helping with integrating those services into iOS and OS X apps. It’s a wrapper, that reduces an overhead of learning yet another framework. Currently it supports 32 different services. Just integrate one of the providers available in ARAnalytics, set it up with API key and it’s done. Library has all the standard tracking features for events, timed events, screen views, and errors. Thanks to using one consistent API, developers can add and drop support for analytics services at will, without going through the hassle of making code changes in many places.

Below I’ll explain how to set up ARAnalytics and take advantage of its great features that will help keep code DRY and get more insight from crash logs.

Read more

Xcode 7/Swift 2 unit testing setup

Automated tests save time and give confidence when refactoring code. How one would go about starting writing tests in Swift? There’s a bunch of ways to do unit testing, different styles (TDD, BDD), different matchers. Before delving into any of this, let’s make sure our testing setup is up to date with Swift 2/Xcode 7 capabilities.

Read more