Swift Defer Statement

Swift 2.0 included a number of new language statements. I recently wrote about the Swift Guard Statement. Defer is another statement new to Swift 2.0. Honestly, I don’t use defer as much as guard, but it can be extremely useful.

What defer does is not obvious at first. Defer will wait to execute a block of code until the current scope (loop, method, etc) is exiting. And it will execute that code whether the scope is exiting cleanly, from a guard, or while an error is being thrown.

Here’s the most basic of examples. The defer block exists before the main body of the code, but it’s not called until afterwards.

func simpleDefer() {
	defer {
		print("Leaving.")
	}
		
	print("Main body of the function.")
}
Simple Defer Statement

This can be useful if, for example, there are resources you need to ensure are cleaned up before leaving the current scope.

You don’t need to limit yourself to a single defer statement. You can use multiple defer statements. When more than one are included, they will be called in reverse order. Think of them being included on a stack and popping them off one at a time.

Here’s a simple example of multiple defer blocks. You can see that the order they are defined and the order they are called is reversed.

func multipleDefer() {
	defer {
		print("one")
	}
	
	defer {
		print("two")
	}
}
Multiple Defer Statements

As I’ve stated above, the defer statement isn’t just limited to exiting from methods. You can include them in loops. Look at this example. Everytime the loop is executed, the defer block is called at the end of each loop.

func simpleLoopDefer() {
	var multiplier: Int = 1
	for i in 0..<5 {
		defer {
			print("loop count: \(i); multiplier: \(multiplier)")
		}
		
		multiplier += multiplier * i
	}
}
Simple Loop Defer Statement

If you’re coming from the world of Objective-C or Java, you can approximate the defer statement with a finally block from a throw statement. The syntax is a little different and in Objective-C and Java, you aren’t allowed to have multiple finally blocks. Here’s a Swift example of a defer block being used like a finally block.

func throwsDefer() {
	defer {
		print("clean up from error and non-error states")
	}
	
	do {
		try methodThatCanThrowError()
	}
	catch {
		print("Why??? What did I do??")
	}
}
Try Catch Defer Statement

There is a caveat to using the defer statement. In a defer code block, you cannot transfer control outside of the current scope. You can’t call “return” out of a function, or “continue” out of a loop.

I believe that defer is one of the lesser used statements in Swift. I don’t think it will be used as often as guard. I could probably utilize defer more than I currently am. But it can be useful, so check it out.

GitHub Repo: rwgrier/swift-defer

OlderNewer