Ensuring the Execution of Code Blocks Before Exiting Methods - Swift 2.0, Xcode 7 and Interface Builder - iOS 9 Swift Programming Cookbook (2015)

iOS 9 Swift Programming Cookbook (2015)

Chapter 1. Swift 2.0, Xcode 7 and Interface Builder

1.3 Ensuring the Execution of Code Blocks Before Exiting Methods

Problem

You have various conditions in your method that can exit the method early. But before you do that, you want to ensure that some code always gets executed, for instance to do some clean-up.

Solution

Use the defer syntax.

Discussion

Anything that you put inside a defer block inside a method is guaranteed to get executed before your method returns to the caller. However, this block of code will get executed after the return call in your method. The code is also called when your method throws an exception.

Let’s say that you want to define a method that takes in a string and renders it inside a new image context with a given size. Now if the string is empty, you want to throw an exception. However, before you do that, we want to make sure that we have ended our image context. Let’s define our error first:

enum Errors : ErrorType{

case EmptyString

}

Then we move onto our actual method that uses the defer syntax:

func imageForString(str: String, size: CGSize) throws -> UIImage{

defer{

UIGraphicsEndImageContext()

}

UIGraphicsBeginImageContextWithOptions(size, true, 0)

if str.characters.count == 0{

throw Errors.EmptyString

}

//draw the string here...

return UIGraphicsGetImageFromCurrentImageContext()

}

I don’t want to put print() statements everywhere in the code because it makes the code really ugly. So to see whether this really works, I suggest that you paste this code into your Xcode--or even better, grab the source code for this book’s example code from GitHub, where I have already placed breakpoints in the defer and the return statements so that you can see that they are working properly.

You can of course then call this method like so:

do{

let i = try imageForString("Foo", size: CGSize(width: 100, height: 50))

print(i)

} catch let excep{

print(excep)

}

See Also