Swift中能否将闭包暴露给Objective-C?用于UISwitch Target是否更优?
关于UISwitch内联闭包作为Target的问题解答
核心结论
没法用一行代码把匿名闭包直接作为#selector的参数——因为target-action机制依赖Objective-C运行时,#selector()要求传入的是被@objc标记的方法,而Swift匿名闭包无法被@objc修饰,所以你最初的写法必然编译失败,也没有语法能直接让闭包在一行内暴露给Objective-C。
关于“内联闭包更快捷”的误区
你觉得内联闭包更快捷的想法其实有偏差:iOS的target-action是基于OC运行时的设计,和Swift闭包的特性天然不兼容。如果硬要实现闭包式回调,反而需要额外的代码来桥接,并不比tag方案更高效。
替代方案对比
1. 你提到的Tag方案(最直接的传统写法)
这个方案的优势是简单、无额外依赖,适合逻辑不复杂的场景:
cell.switch.tag = switchNumber cell.switch.addTarget(self, action: #selector(switchFlipped), for: .valueChanged)
@objc func switchFlipped(sender: UISwitch){ let switchNumber = sender.tag switch switchNumber { // 根据不同tag处理对应数组元素 } }
2. 闭包式回调(需扩展实现)
如果想避免使用tag(比如怕tag冲突、想更直观地绑定逻辑),可以通过关联对象给UISwitch扩展一个闭包属性,间接实现闭包回调,但这需要提前写扩展代码:
import ObjectiveC private var SwitchClosureKey: UInt8 = 0 extension UISwitch { typealias ValueChangedHandler = (UISwitch) -> Void var valueChangedHandler: ValueChangedHandler? { get { return objc_getAssociatedObject(self, &SwitchClosureKey) as? ValueChangedHandler } set { objc_setAssociatedObject(self, &SwitchClosureKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) addTarget(self, action: #selector(handleValueChanged), for: .valueChanged) } } @objc private func handleValueChanged() { valueChangedHandler?(self) } }
使用时可以直接绑定闭包:
cell.switch.valueChangedHandler = { switchControl in // 这里可以通过tableView获取switch所在cell的indexPath,再操作对应数组元素 // 比如: guard let indexPath = self.tableView.indexPath(for: cell) else { return } yourArray[indexPath.row] = switchControl.isOn }
这个方案虽然实现了闭包回调,但前期需要编写扩展代码,并不比tag方案“快捷”。
总结
你想要的“一行内联闭包作为Selector”是无法实现的。如果场景简单,Tag方案是最直接高效的选择;如果想避免使用tag,可以考虑上述的闭包扩展方案,但它并没有想象中那么“快捷”。
内容的提问来源于stack exchange,提问作者Afinainflowers
相关产品推荐
相关产品推荐

