如何将闭包作为变量传递?
How to pass closure as a variable?
我有以下来自 playground 的代码:
class MyButton {
var pressed: (() -> Void)?
func press() {
pressed?()
}
}
class SomeView {
var buttonDidPressed: (() -> Void)?
let button = MyButton()
init() {
button.pressed = buttonDidPressed
}
func press() {
button.press()
}
}
let view = SomeView()
view.buttonDidPressed = {
print("pressed")
}
view.press()
MyButton
有闭包 pressed
,它在调用 press
时执行。在 SomeView
s init 中,我为 pressed
闭包赋值。当然,在初始化时,它是nil
。但是在 SomeView
初始化之后,我给那个 buttonDidPressed
闭包赋值。因为,闭包是引用类型,当 view.press
被调用时, buttonDidPressed
不应该是 nil。但是,无论如何,我的打印没有执行。为什么?
您首先初始化 SomeView
(调用 init
函数),然后设置 buttonDidPressed
属性。所以,buttonDidPressed
属性 有你的闭包,但从未将它传递给 MyButton
实例。
您可以使用didSet
立即更新:
class SomeView {
var buttonDidPressed: (() -> Void)? {
didSet {
button.pressed = buttonDidPressed
}
}
let button = MyButton()
func press() {
button.press()
}
}
更新:你也可以像这样在SomeView
的初始化器中传递你的闭包:
class SomeView {
let button = MyButton()
init(buttonDidPressed: (() -> Void)?) {
button.pressed = buttonDidPressed
}
func press() {
button.press()
}
}
let view = SomeView {
print("pressed")
}
view.press()
其实这个问题最好用绑定来解释,比方说:
class Sekoya<T> {
typealias Listener = (T) -> Void
var listenerHolder: Listener?
var value: T {
didSet {
listenerHolder?(value) // when value change listenerHolder triger
}
}
init(_ value: T) {
self.value = value
}
func bind(listener: Listener?) {
self.listenerHolder = listener // referencing listener my closure variable in SomeView Class
listener?(value)
}
}
让我们在另一个地方使用这个绑定 class:
let sekoyaInt = Sekoya(25)
sekoyaInt.bind {
print("value changed: \([=11=])")
}
每当您更改值时,您的引用闭包将被触发并且值将被更改并打印值
以下是我认为您想要实现的目标:
class SomeView {
var buttonDidPressed: (() -> Void)? = nil {
didSet {
button.pressed = buttonDidPressed
}
}
let button = MyButton()
func press() {
button.press()
}
}
您的代码无法正常工作的原因是因为在 SomeView.init
中,buttonDidPressed
是 nil
- 即缺少参考。所以:
buttonDidPressed = nil
button.pressed = buttonDidPressed
// is equivalent to
button.pressed = nil
稍后为 buttonDidPressed
分配新的(或不同的)引用不会更改 button.pressed
属性。
我有以下来自 playground 的代码:
class MyButton {
var pressed: (() -> Void)?
func press() {
pressed?()
}
}
class SomeView {
var buttonDidPressed: (() -> Void)?
let button = MyButton()
init() {
button.pressed = buttonDidPressed
}
func press() {
button.press()
}
}
let view = SomeView()
view.buttonDidPressed = {
print("pressed")
}
view.press()
MyButton
有闭包 pressed
,它在调用 press
时执行。在 SomeView
s init 中,我为 pressed
闭包赋值。当然,在初始化时,它是nil
。但是在 SomeView
初始化之后,我给那个 buttonDidPressed
闭包赋值。因为,闭包是引用类型,当 view.press
被调用时, buttonDidPressed
不应该是 nil。但是,无论如何,我的打印没有执行。为什么?
您首先初始化 SomeView
(调用 init
函数),然后设置 buttonDidPressed
属性。所以,buttonDidPressed
属性 有你的闭包,但从未将它传递给 MyButton
实例。
您可以使用didSet
立即更新:
class SomeView {
var buttonDidPressed: (() -> Void)? {
didSet {
button.pressed = buttonDidPressed
}
}
let button = MyButton()
func press() {
button.press()
}
}
更新:你也可以像这样在SomeView
的初始化器中传递你的闭包:
class SomeView {
let button = MyButton()
init(buttonDidPressed: (() -> Void)?) {
button.pressed = buttonDidPressed
}
func press() {
button.press()
}
}
let view = SomeView {
print("pressed")
}
view.press()
其实这个问题最好用绑定来解释,比方说:
class Sekoya<T> {
typealias Listener = (T) -> Void
var listenerHolder: Listener?
var value: T {
didSet {
listenerHolder?(value) // when value change listenerHolder triger
}
}
init(_ value: T) {
self.value = value
}
func bind(listener: Listener?) {
self.listenerHolder = listener // referencing listener my closure variable in SomeView Class
listener?(value)
}
}
让我们在另一个地方使用这个绑定 class:
let sekoyaInt = Sekoya(25)
sekoyaInt.bind {
print("value changed: \([=11=])")
}
每当您更改值时,您的引用闭包将被触发并且值将被更改并打印值
以下是我认为您想要实现的目标:
class SomeView {
var buttonDidPressed: (() -> Void)? = nil {
didSet {
button.pressed = buttonDidPressed
}
}
let button = MyButton()
func press() {
button.press()
}
}
您的代码无法正常工作的原因是因为在 SomeView.init
中,buttonDidPressed
是 nil
- 即缺少参考。所以:
buttonDidPressed = nil
button.pressed = buttonDidPressed
// is equivalent to
button.pressed = nil
稍后为 buttonDidPressed
分配新的(或不同的)引用不会更改 button.pressed
属性。