我碰巧在侧边栏中看到了这个,我最近也遇到了同样的问题。不幸的是,由于 Objective-C 运行时的限制,你不能在协议扩展上使用@objc,我相信这个问题在今年早些时候已经解决了。
问题出现是因为扩展是在协议一致性之后添加的,因此无法保证满足协议一致性。也就是说,有可能从任何继承 NSObject 并符合协议的对象中调用方法作为选择器。这通常通过委托来完成。
这意味着您可以创建一个符合协议的空包装器子类,并使用包装器从包装器中定义的协议调用其方法,协议中任何其他未定义的方法都可以传递给委托。还有其他类似的解决方案使用具体类的私有扩展,例如 UIViewController 并定义一个调用协议方法的方法,但这些也与特定类相关联,而不是碰巧发生的特定类的默认实现符合协议。
意识到您正在尝试实现一个协议函数的默认实现,该函数使用另一个它自己的协议函数来为其自己的实现定义一个值。哇!
协议:
public protocol CustomViewDelegate {
func update()
func nonDelegatedMethod()
}
查看:
使用委托,并定义包装方法以安全地解开委托的方法。
class CustomView: UIView {
let updateButton: UIButton = {
let button = UIButton(frame: CGRect(origin: CGPoint(x: 50, y: 50), size: CGSize(width: 150, height: 50)))
button.backgroundColor = UIColor.lightGray
button.addTarget(self, action: #selector(doDelegateMethod), for: .touchUpInside)
return button
}()
var delegate:CustomViewDelegate?
required init?(coder aDecoder: NSCoder) {
fatalError("Pew pew, Aghh!")
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(updateButton)
}
@objc func doDelegateMethod() {
if delegate != nil {
delegate!.update()
} else {
print("Gottfried: I wanted to be a brain surgeon, but I had a bad habit of dropping things")
}
}
}
视图控制器:
使视图控制器符合视图的委托:并实现协议的方法。
class ViewController: UIViewController, CustomViewDelegate {
let customView = CustomView(frame: CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: 200, height: 200)))
override func viewDidLoad() {
super.viewDidLoad()
customView.backgroundColor = UIColor.red
customView.delegate = self //if delegate is not set, the app will not crash
self.view.addSubview(customView)
}
// Protocol -> UIView Button Action -> View Controller's Method
func update() {
print("Delegating work from View that Conforms to CustomViewDelegate to View Controller")
}
//Protocol > View Controller's Required Implementation
func nonDelegatedMethod() {
//Do something else
}
}
请注意,视图控制器只需要符合委托并且没有设置视图某些属性的选择器,这将视图(及其协议)与视图控制器分开。
您已经有一个名为 TapView 的 UIView,它继承自 UIView 和 Tappable,因此您的实现可以是:
协议:
protocol TappableViewDelegate {
func tapGestureDetected(gesture:UITapGestureRecognizer)
}
TappableView:
class TappableView: UIView {
var delegate:TappableViewDelegate?
required init?(coder aDecoder: NSCoder) {
fatalError("Pew pew, Aghh!")
}
override init(frame: CGRect) {
super.init(frame: frame)
let gesture = UITapGestureRecognizer(target: self, action: #selector(doDelegateMethod(gesture:)))
addGestureRecognizer(gesture)
}
@objc func doDelegateMethod(gesture:UITapGestureRecognizer) {
if delegate != nil {
delegate!.tapGestureDetected(gesture: gesture)
} else {
print("Gottfried: I wanted to be a brain surgeon, but I had a bad habit of dropping things")
}
}
}
视图控制器:
class ViewController: UIViewController, TappableViewDelegate {
let tapView = TappableView(frame: CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: 200, height: 200)))
override func viewDidLoad() {
super.viewDidLoad()
tapView.backgroundColor = UIColor.red
tapView.delegate = self
self.view.addSubview(tapView)
}
func tapGestureDetected(gesture: UITapGestureRecognizer) {
print("User did tap")
}
}