我有一个协议扩展,它曾经在swift 2.2之前完美地工作 .
现在我有一个警告,告诉我使用新的 #selector
,但如果我添加它
没有使用Objective-C Selector声明的方法 .
我尝试在这几行代码中重现这个问题,可以很容易地复制并粘贴到游乐场
protocol Tappable {
func addTapGestureRecognizer()
func tapGestureDetected(gesture:UITapGestureRecognizer)
}
extension Tappable where Self: UIView {
func addTapGestureRecognizer() {
let gesture = UITapGestureRecognizer(target: self, action:#selector(Tappable.tapGestureDetected(_:)))
addGestureRecognizer(gesture)
}
}
class TapView: UIView, Tappable {
func tapGestureDetected(gesture:UITapGestureRecognizer) {
print("Tapped")
}
}
还有一个建议是在协议 @objc
中附加到该方法,但如果我这样做也要求我将它添加到实现它的类中,但是一旦我添加了类,那么似乎没有看到协议中的实现延期 .
我该如何正确实现?
5 回答
我遇到了类似的问题 . 这就是我做的 .
将协议标记为@objc .
将我使用默认行为扩展的任何方法标记为可选 .
然后使用Self . 在#selector中 .
您可以创建一个属性作为选择器...示例:
错误停止显示,并且不再需要使用@objc装饰器设置协议和类 .
这个解决方案不是最优雅的,但直到现在看起来还不错 .
这个答案与Bruno Hecktheuers非常相似,但是我们选择将它作为参数传递给addTapGestureRecognizer函数,而不是让每个想要符合“Tappable”协议的人实现变量“selector” .
然后只需将选择器传递到任何地方:
这样我们就可以避免让实现此协议的人必须实现选择器变量,并且我们也避免使用“@objc”标记每个人使用此协议 . 像这种方法的感觉不那么臃肿 .
这是一个使用Swift 3的工作示例 . 它使用标准的Swift协议,无需任何
@objc
装饰和私有扩展来定义回调函数 .我碰巧在侧栏看到这个,我最近遇到了同样的问题..不幸的是,由于Objective-C运行时限制你不能在协议扩展上使用@objc,我相信这个问题在今年年初就已经关闭了 .
出现这个问题是因为在协议符合性之后添加了扩展,因此无法保证满足协议的一致性 . 也就是说,可以从NSObject子类和符合协议的任何东西中调用方法作为选择器 . 这通常是通过授权完成的 .
这意味着您可以创建一个符合协议的空包装子类,并使用包装器从包装器中定义的协议调用其方法,协议中的任何其他未定义方法都可以传递给委托 . 还有其他类似的解决方案使用具体类的私有扩展,如UIViewController,并定义一个调用协议方法的方法,但这些方法也绑定到一个特定的类,而不是特定类的默认实现,恰好符合协议 .
意识到您正在尝试实现协议函数的默认实现,该函数使用其自己的另一个协议函数来为其自己的实现定义值 . 噢!
Protocol:
View:
使用委托,并定义一个包装器方法来安全地解包委托的方法 .
ViewController:
使View Controller符合视图的委托:并实现协议的方法 .
请注意,视图控制器只需要符合委托,并且没有设置视图的某些属性的选择器,这将视图(和它的协议)与视图控制器分开 .
您已经有一个名为TapView的UIView,它继承自UIView和Tappable,因此您的实现可能是:
Protocol:
TappableView:
ViewController: