我正在尝试将闭包作为参数快速传递并在选择器方法中执行。
override func viewDidLoad() {
super.viewDidLoad()
let closure = {
print(self.isCityChoosen)
}
perform(#selector(foo(param:)), with: closure)
}
@objc func foo(param: () -> () ) {
param()
}
但是我有
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
执行param()时运行时错误
为什么会发生此错误?
有办法解决吗?
答案 0 :(得分:6)
您的闭包不是Objective-C块,因此无法通过ObjC运行时传递。您必须使用@convention
将其标记为块。
let closure: @convention(block) () -> Void = { ... }
您可以通过分配现有的闭包将其转换为块:
let closure = { ... }
let block: @convention(block) () -> Void = closure
perform(#selector(foo(param:)), with: block)
Objective-C块实际上是对象,并参与ARC。之所以发生崩溃,是因为perform
试图在非阻塞状态下调用Block_copy
。
当然,选择器并不是Swift中合适的工具,因此您应该将任何基于选择器的接口转换为仅使用函数参数。如果您发现自己使用perform
,则可能是您在Swift中走错了路。但是如果需要,它仍然可用。
答案 1 :(得分:1)
是否有使用perform(_:with:)
的理由?如果不是这样,您可以简化代码,只需使用闭包
override func viewDidLoad() {
super.viewDidLoad()
foo {
print(self.isCityChoosen)
}
}
func foo(param: () -> () ) {
param()
}
答案 2 :(得分:1)
我认为这是因为您在方法声明中使用了非object-c类型:
@objc func foo(param: () -> ())
闭包不是Objective-C类型。
您可以执行以下操作;
@objc func foo(_ closure: Any) {
if let closure = closure as? () -> Void {
closure()
}
}
之所以起作用,是因为(我猜)您告诉objc运行时该方法接受Any
,该id
正确地转换为object-c类型IMPORTRANGE
。