Exception in Swift 2 for Java Developers

For Java developers Swift 2 has a familiar but strangely different exception handling system. An exception type must implement the ErrorType protocol. It’s an empty protocol so there is no method to implement.

class AppError : ErrorType {
    var message : String

    init(message: String) {
        self.message = message
    }
}

A function that needs to throw an exception must delcare the intention in its signature using the throws keyword. This is similar to Java except that no exception data type needs to be specified.

func evenSquared(val : Int) throws -> Int {
    if val % 2 == 0 {
        return val * val
    }

    throw AppError(message: "Not an even number")
}

If you call a function that throws exception you must either catch the exception or throw it again. This again is same as in Java. Catching exception is strangely different from Java. The code is wrapped in a do block. Each function that throws exception must be called using a try keyword.

func test() {
    do {
        let v = try evenSquared(3)
        print("return: \(v)")
    } catch let e as AppError {
        print("Application error: \(e.message)")
    } catch {
        print("Something else is wrong") //Catch all
    }
}

Note, as of Swift 2 you must have a catch all block. Otherwise you will get a compilation error – Errors thrown from here are not handled because the enclosing catch is not exhaustive. This is because we don’t specify the data type of the thrown exception in the function signature and the compiler has no way of knowing if you have handled all possible scenarios. This is pretty dumb IMHO.

In some cases an exception may be unrecoverable. Crashing the app will be the only option in that case. Coding for this situation is easy using try!.

func test() {
    let v = try! evenSquared(3)

    print("return: \(v)")
}

In this case the program will abort if evenSquared() throws an exception. Otherwise, the return value will be assigned to v.

You can also convert the value returned by a function that throws exception into an optional. This is done using try?.

func test() {
    let v = try? evenSquared(3)

    if let val = v {
        print("return: \(val)")
    } else {
        print("evenSquared failed.")
    }
}

I am not a huge fan of try? because it doesn’t reduce code size in any way and you lose the actual exception object that was thrown.

The functionality of Java’s finally block is achieved with the defer block in Swift. A defer block simply delays execution of the block until the enclosing block finishes.

func test() {
    defer {
        print("Defer block 1")
    }
    defer {
        print("Defer block 2")
    }
}

The defer blocks are executed in reverse order as they are encountered. So, the above will print:

Defer block 2
Defer block 1

A defer blocks executes at the end of the parent block.

func test() {
    if true {
        defer {
            print("Defer block 1")
        }
    }
    defer {
        print("Defer block 2")
    }
}

The above will print:

Defer block 1
Defer block 2

That is because the first defer block is within an if block that ends before the function block.

A defer block is not executed if it is not encountered during program execution.

func test(num : Int) {
    defer {
        print("Defer block 1")
    }
    if true {
        return
    }
    defer {
        print("Defer block 2")
    }
}

The above will print:

Defer block 1

The second defer block is never encountered and will not be executed.

In Swift you can clean up resources from the destructor (dinit block) of a class. This is not possible in Java. So you should not need to use defer blocks all that much. But they are useful for cleaning up resources that are not cleaned up by a destructor. For example, you can clean up temporary files created within a function.

func test() {
    var tmpFile = ... //Code to create a temp file
    defer {
        //Delete the temp file
    }
    //Do other things
}

Full Screen Page View Controller

I think UIPageViewController has a pretty ugly API. Also it does not do fullscreen which is what most apps need. So I have created FullScreenPageViewController. With that class you don’t have to implement the crazy UIPageViewControllerDataSource protocol. Simply supply all the child view controllers at the time of creating a new instance of FullScreenPageViewController. Example:

//Create the child view controllers
let vc1 = storyboard!.instantiateViewControllerWithIdentifier(
    "PageOneViewController")
let vc2 = storyboard!.instantiateViewControllerWithIdentifier(
    "PageTwoViewController")

//Create the page view controller
self.pageViewController = FullScreenPageViewController(
    childControllers: [vc1, vc2])

//Show the page view controller
self.view.addSubview(self.pageViewController.view)