Reputation: 7330
Coming from a different language background where passing a method to another object was done differently as demonstrated below (approach A) but I've noticed a style of passing blocks around in Objective-C as well as SWIFT, what's the recommended way in SWIFT and why? (pros and cons any?)
class Messenger {
private var _method: ((String) -> ())
init(method: (String -> ())) {
_method = method
}
}
class Test {
init() {
Messenger(method: self.callback) //approach A
Messenger({
message in self.callback(message) //approach B - Wrapper/Block style
})
}
func callback(message: String) {
println(message)
}
}
Upvotes: 2
Views: 866
Reputation: 40965
Your method A is the way to go. Method B really doesn’t serve a purpose – you are declaring an anonymous function which takes a single parameter and does nothing to it but use it as an argument to another function, callback
. It’s essentially like saying this:
func f(arg1: Int) {
// do nothing but call g
g(arg1)
}
f(1) // no different to calling g(1)
takeFunc(f) // no different to passing in g
It’s important to realize that a function declared with the closure expression syntax, let f: Int->Bool = { i in etc }
, and a function declared with the func
keyword, func f(i: Int)->Bool { etc }
amount to much the same thing. There are subtle differences but not fundamental ones.
Re your concerns about strong references – the closure expression in option B doesn’t really help the situation. In option A you pass an implicit reference to self by passing in a pointer to an instance's member function. In Option B, you declare an anonymous closure that “captures” self
, and then pass that, but that anonymous function being stored will keep self
alive in just the same way storing self.memfun
will, just with an extra level of indirection. In fact, it’s so easy to forget that capturing self
via a closure expression can be a risk that Swift will warn you if you do it implicitly by accident and force you to put an explicit self
in there (which can be super-annoying sometimes when you know the capture isn’t an issue e.g. when referencing self
in a call to map
or filter
).
To write a callback function that didn’t capture self, you would have to use a capture list:
Messenger { [weak self] message in // weak or unowned depending on how Messenger is being used
self?.callback(message) // if weak, self needs to be optional
return // return needed since otherwise it will attempt to return ()?
}
By the way, the best way to write more Swift-y Swift would be to ditch a lot of the excess brackets :-)
e.g.
// no need to wrap entire function type in (),
// and single argument types (i.e. 1-element tuples)
// don’t need () surrounding them:
private var _method: String -> ()
instead of
private var _method: ((String) -> ())
and
Messenger { // closure exprs can be outside the () of functions
// when they’re the last argument (and () can be
// left out completely when they’re the only argument)
message in self.callback(message)
}
instead of
Messenger({
message in self.callback(message) //approach B - Wrapper/Block style
})
Upvotes: 3
Reputation: 12660
Your approach B will allow you to insert additional statements between message in
and self.callback(message)
. Without such additional statements (as in your verbatim example) I would favor approach A.
Upvotes: 0