在Swift中将函数分配给块时捕获语义?
问题描述:
我想知道当你在内存管理方面(即我想避免一个保留周期)在Swift中为一个块分配一个函数时它意味着什么。在Swift中将函数分配给块时捕获语义?
例如,假设我有如下定义按钮:
class Button {
var wasTapped:() -> Void
}
我用它在一个视图控制器像这样:
class ViewController {
let button: Button
func setUpButtonHandler() {
button.wasTapped = ...
}
func buttonWasTapped() {
// do something
}
}
我的问题是关于button.wasTapped = ...
分配。
显然,如果我把它像这样:
button.wasTapped = { self.buttonWasTapped() }
我刚刚创建了一个保留周期:视图控制器 - >按钮 - >视图控制器。
然而,斯威夫特让我做这件事,而不是:
button.wasTapped = buttonWasTapped
它是安全的这样做呢? (即,这是否会阻止保留周期?)
答
这仍然会创建保留周期。
一个好办法去想它是认识到,任何时候你看到:
button.wasTapped = buttonWasTapped
这只是为速记:
button.wasTapped = { self.buttonWasTapped() }
这显然会创建一个保留周期,明确使用self
清楚地表明。
这很混乱,因为保留周期在第二个版本中很明显,但不是第一个。
不幸的是,这意味着你将需要坚持到更详细的(并保留周期避免):
button.wasTapped = { [weak self] in self?.buttonWasTapped() }
您可以验证这个操场这种行为:
class Button {
var wasTapped:() -> Void
init() {
wasTapped = {}
}
}
class ViewController {
let button: Button
func setUpButtonHandler() {
//button.wasTapped = { [weak self] in self?.buttonWasTapped() } // no retain cycle
//button.wasTapped = { self.buttonWasTapped() } // retain cycle
//button.wasTapped = buttonWasTapped // retain cycle
}
func buttonWasTapped() {
print("tapped!")
}
init() {
button = Button()
setUpButtonHandler()
}
deinit {
print("deinit")
}
}
func test() {
let vc = ViewController()
vc.button.wasTapped()
}
test()
更新:更多详情可以fo und here:Function references in Swift and retain cycles
帮助文章:) +1 –