The Genius of Swift 2's defer
/Swift 2.0 has introduced (amongst many other things) a new defer keyword. Simply put it allows you to do something after a block exits, but but before control is passed to the caller.
For example, you want to record that an operation occurred, regardless of whether or not it was successful. Previously you might have written:
struct MyRequest{ var callCount = 0 func tryRequest()->Bool{ //... //Some Code //... return requestResult } func makeRequest()->RequestResponse{ callCount++ if tryRequest(){ //It worked, do something return RequestResponse() } else { //It didn't work, do something else return ErrorResponse() } } }
Seems pretty simple, but what if there is a limit to the number of retries you are allowed? Let's assume we have a global (I know, I know, but it's just an example) named MAX_RETRIES that specifies the limit. We probably don't want callCount to be incremented if makeRequest fails because another request would exceed the retry count. So we would do
func makeRequest(){ if callCount == MAX_RETRIES { return } if tryRequest(){ callCount++ //It worked, do something return RequestResponse() } else { callCont++ //It didn't work, do something else return ErrorResponse() } }
Now of course we should really be throwing here, and we could factor this to store a response that was set by each branch of the if statement. However, in both the obvious patterns we begin to obfuscate the algorithm we are trying to implement with the flow control. The algorithm really is "If we are below the maximum number of retries, make the request, increment the call count and return"
Swift 2.0 makes it possible to capture this perfectly.
func makeRequest(){ if callCount == MAX_RETRIES { return } defer{ callCount++ } if tryRequest(){ //It worked, do something return RequestResponse() } else { //It didn't work, do something else return ErrorResponse() } }
The block following defer will be called AFTER either of the returns is called, but before control returns to the controller. The genius is it, like so many things in Swift, allows us to express our algorithm very naturally.