How do I properly reference self in a swift closure?
dispatch_async(dispatch_get_main_queue()) {
self.popViewControllerAnimated(true)
}
I get the error:
Cannot convert the expression's type 'Void' to type 'UIViewController!"
Randomly I tried:
dispatch_async(dispatch_get_main_queue()) { ()
self.popViewControllerAnimated(true)
}
and it worked. Not sure what the extra () does! Anyone care to explain? Thanks!
This is the same issue as people have run in with these questions:
What am I doing wrong in Swift for calling this Objective-C block/API call?
animateWithDuration:animations:completion: in Swift
Here is the general idea:
From the Swift book: https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Closures.html
One of the optimizations of Closures is:
Implicit returns from single-expression closures
Thus, if you just have one line in your closure, your closure's return value changes. In this case, popViewController
returns the view controller being popped. By adding ()
to the closure, you just made it a 2-line closure and the return value isn't implicit anymore!
I answered something like this a couple of days ago for a related issue re: Swift's 'implicit return value for single-expression closure': animateWithDuration:animations:completion: in Swift
In this case, the method popViewControllerAnimated
returns the UIViewController that was popped from the stack: (https://developer.apple.com/library/ios/documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html#//apple_ref/occ/instm/UINavigationController/popViewControllerAnimated:)
Even though you aren't explicitly doing anything with the return value of that method, Swift is using that value (the returned UIViewController) as the return value for the closure - however, the closure is expecting a return value of Void.
When you added the extra parens ()
, you essentially added another line to the closure, and since it is no longer a 'single-expression closure' it no longer implicit returns the popped UIViewController.
The community will eventually settle on a convention for handling this, for now when I have been running into it I have been advocating adding return ()
to the end of the closure (as it clearly states the intention, (1) short circuiting the 'implicit return' by adding another statement, and (2) explicitly returning what was expected).