传递直接引用或关闭
pass direct reference or closure
来自不同的语言背景,其中将方法传递给另一个对象的方式不同,如下所示(方法 A),但我注意到 Objective-C 和 [= 中传递块的风格14=],SWIFT 中推荐的方法是什么?为什么? (有利有弊?)
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)
}
}
您的方法 B 将允许您在 message in
和 self.callback(message)
之间插入额外的语句。如果没有这样的附加声明(如您的逐字示例),我会赞成方法 A.
您的方法 A 是可行的方法。方法 B 确实没有用处——您正在声明一个匿名函数,它接受一个参数并且不对它做任何事情,而是将它用作另一个函数的参数,callback
。本质上就像这样说:
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
重要的是要认识到,使用闭包表达式语法 let f: Int->Bool = { i in etc }
声明的函数和使用 func
关键字声明的函数 func f(i: Int)->Bool { etc }
几乎是同一回事。有细微的差别,但不是根本性的。
关于强引用的担忧 - 选项 B 中的闭包表达式并没有真正帮助这种情况。在选项 A 中,您通过传入指向实例成员函数的指针来传递对 self 的隐式引用。在选项 B 中,您声明一个“捕获”self
的匿名闭包,然后传递它,但是存储的匿名函数将以与存储 self.memfun
相同的方式使 self
保持活动状态,只是有一个额外的间接级别。事实上,很容易忘记通过闭包表达式捕获 self
可能存在风险,如果你不小心隐式地捕获 Swift 并强制你放置一个显式的 self
,那么 Swift 会警告你] 在那里(当你知道捕获不是问题时,有时会非常烦人,例如在调用 map
或 filter
时引用 self
)。
要编写不捕获 self 的回调函数,您必须使用 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 ()?
}
顺便说一下,写更多 Swift-y Swift 的最好方法是去掉很多多余的括号 :-)
例如
// 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 -> ()
而不是
private var _method: ((String) -> ())
和
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)
}
而不是
Messenger({
message in self.callback(message) //approach B - Wrapper/Block style
})
来自不同的语言背景,其中将方法传递给另一个对象的方式不同,如下所示(方法 A),但我注意到 Objective-C 和 [= 中传递块的风格14=],SWIFT 中推荐的方法是什么?为什么? (有利有弊?)
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)
}
}
您的方法 B 将允许您在 message in
和 self.callback(message)
之间插入额外的语句。如果没有这样的附加声明(如您的逐字示例),我会赞成方法 A.
您的方法 A 是可行的方法。方法 B 确实没有用处——您正在声明一个匿名函数,它接受一个参数并且不对它做任何事情,而是将它用作另一个函数的参数,callback
。本质上就像这样说:
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
重要的是要认识到,使用闭包表达式语法 let f: Int->Bool = { i in etc }
声明的函数和使用 func
关键字声明的函数 func f(i: Int)->Bool { etc }
几乎是同一回事。有细微的差别,但不是根本性的。
关于强引用的担忧 - 选项 B 中的闭包表达式并没有真正帮助这种情况。在选项 A 中,您通过传入指向实例成员函数的指针来传递对 self 的隐式引用。在选项 B 中,您声明一个“捕获”self
的匿名闭包,然后传递它,但是存储的匿名函数将以与存储 self.memfun
相同的方式使 self
保持活动状态,只是有一个额外的间接级别。事实上,很容易忘记通过闭包表达式捕获 self
可能存在风险,如果你不小心隐式地捕获 Swift 并强制你放置一个显式的 self
,那么 Swift 会警告你] 在那里(当你知道捕获不是问题时,有时会非常烦人,例如在调用 map
或 filter
时引用 self
)。
要编写不捕获 self 的回调函数,您必须使用 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 ()?
}
顺便说一下,写更多 Swift-y Swift 的最好方法是去掉很多多余的括号 :-)
例如
// 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 -> ()
而不是
private var _method: ((String) -> ())
和
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)
}
而不是
Messenger({
message in self.callback(message) //approach B - Wrapper/Block style
})