Ios 协议扩展编译器中的Swift 2.2#选择器错误

Ios 协议扩展编译器中的Swift 2.2#选择器错误,ios,swift,protocols,Ios,Swift,Protocols,我有一个协议扩展,它在swift 2.2之前工作得很好。 现在我有一个警告,告诉我使用新的#选择器,但是如果我添加它 没有使用Objective-C选择器声明方法。 我试图在这几行代码中重现这个问题,这些代码可以很容易地复制并粘贴到游戏中 protocol Tappable { func addTapGestureRecognizer() func tapGestureDetected(gesture:UITapGestureRecognizer) } extension

我有一个协议扩展,它在swift 2.2之前工作得很好。

现在我有一个警告,告诉我使用新的
#选择器
,但是如果我添加它

没有使用Objective-C选择器声明方法。

我试图在这几行代码中重现这个问题,这些代码可以很容易地复制并粘贴到游戏中

  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
中附加到该方法,但如果我这样做,它也会要求我将其添加到实现它的类中,但一旦我添加了该类,该类就不再符合协议,因为它似乎看不到协议扩展中的实现。

我如何才能正确地实现这一点?

我遇到了类似的问题。这就是我所做的

  • 将协议标记为@objc
  • 将使用默认行为扩展的任何方法标记为可选
  • 然后用Self。在#选择器中

    @objc public protocol UpdatableUserInterfaceType {
      optional func startUpdateUITimer()
      optional var updateInterval: NSTimeInterval { get }
      func updateUI(notif: NSTimer)
    }
    
    public extension UpdatableUserInterfaceType where Self: ViewController {
    
      var updateUITimer: NSTimer {
        return NSTimer.scheduledTimerWithTimeInterval(updateInterval, target: self, selector: #selector(Self.updateUI(_:)), userInfo: nil, repeats: true)
      }
    
      func startUpdateUITimer() {
        print(updateUITimer)
      }
    
      var updateInterval: NSTimeInterval {
        return 60.0
      }
    }
    

  • 您可以创建一个作为选择器的属性。。。例如:

    protocol Tappable {
        var selector: Selector { get }
        func addTapGestureRecognizer()
    }
    
    extension Tappable where Self: UIView {
        func addTapGestureRecognizer() {
            let gesture = UITapGestureRecognizer(target: self, action: selector)
            addGestureRecognizer(gesture)
        }
    }
    
    class TapView: UIView, Tappable {
        var selector = #selector(TapView.tapGestureDetected(_:))
    
        func tapGestureDetected(gesture:UITapGestureRecognizer) {
            print("Tapped")
        }
    }
    
    错误停止显示,不需要使用@objc decorator设置协议和类


    此解决方案不是最优雅的,但到目前为止看起来还不错。

    此答案与Bruno Hecktheuers非常相似,但不是让所有想要遵守“Tappable”协议的人都实现变量“selector”,而是选择将其作为参数传递给AddTapGestureRecognitizer函数:

    protocol Tappable {
        func addTapGestureRecognizer(selector selector: Selector)
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    extension Tappable where Self: UIView {
        func addTapGestureRecognizer(selector selector: Selector)
            let gesture = UITapGestureRecognizer(target: self, action: selector)
            addGestureRecognizer(gesture)
        }
    }
    
    class TapView: UIView, Tappable {    
        func tapGestureDetected(gesture:UITapGestureRecognizer) {
            print("Tapped")
        }
    }
    
    然后只要将选择器传递到使用它的任何位置:

    addTapGestureRecognizer(selector: #selector(self.tapGestureDetected(_:)))
    

    通过这种方式,我们避免了实现此协议的人必须实现选择器变量,也避免了使用此协议的每个人都必须用“@objc”标记。感觉这种方法没有那么臃肿。

    下面是一个使用Swift 3的工作示例。它使用标准的Swift协议,不需要任何
    @objc
    装饰和私有扩展来定义回调函数

    protocol PlayButtonPlayable {
    
        // be sure to call addPlayButtonRecognizer from viewDidLoad or later in the display cycle
        func addPlayButtonRecognizer()
        func handlePlayButton(_ sender: UITapGestureRecognizer)
    
    }
    
    fileprivate extension UIViewController {
        @objc func _handlePlayButton(_ sender: UITapGestureRecognizer) {
            if let playable = self as? PlayButtonPlayable {
                playable.handlePlayButton(sender)
            }
        }
    }
    
    fileprivate extension Selector {
        static let playTapped =
            #selector(UIViewController._handlePlayButton(_:))
    }
    
    extension PlayButtonPlayable where Self: UIViewController {
    
        func addPlayButtonRecognizer() {
            let playButtonRecognizer = UITapGestureRecognizer(target: self, action: .playTapped)
            playButtonRecognizer.allowedPressTypes = [ NSNumber(value: UIPressType.playPause.rawValue as Int) ]
            view.addGestureRecognizer(playButtonRecognizer)
        }
    
    }
    

    我碰巧在侧栏中看到了这一点,我最近也遇到了同样的问题。。不幸的是,由于Objective-C运行时的限制,您不能在协议扩展上使用@objc,我相信这个问题在今年年初就解决了

    问题的出现是因为扩展是在协议一致性之后添加的,因此无法保证满足协议一致性。也就是说,可以从属于NSObject子类且符合协议的任何对象中调用方法作为选择器。这通常是通过授权来完成的

    这意味着您可以创建符合协议的空包装器子类,并使用包装器从包装器中定义的协议调用其方法,协议中任何其他未定义的方法都可以传递给委托。还有其他类似的解决方案,它们使用具体类(如UIViewController)的私有扩展,并定义一个调用协议方法的方法,但它们也绑定到特定类,而不是碰巧符合协议的特定类的默认实现

    请注意,您正在尝试实现一个协议函数的默认实现,该协议函数使用它自己的另一个协议函数为它自己的实现定义一个值。唷

    协议:

     public protocol CustomViewDelegate {
         func update()
         func nonDelegatedMethod()
    }
    
    protocol TappableViewDelegate {
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    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")
       }
    
    }
    
    查看:

     public protocol CustomViewDelegate {
         func update()
         func nonDelegatedMethod()
    }
    
    protocol TappableViewDelegate {
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    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")
       }
    
    }
    
    使用委托,并定义包装方法以安全地展开委托的方法

    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 
    
       }
    }
    
    视图控制器:

     public protocol CustomViewDelegate {
         func update()
         func nonDelegatedMethod()
    }
    
    protocol TappableViewDelegate {
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    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")
       }
    
    }
    
    使视图控制器符合视图的委托:并实现协议的方法

    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继承自UIView并可用于Tappable,因此您的实现可以是:

    协议:

     public protocol CustomViewDelegate {
         func update()
         func nonDelegatedMethod()
    }
    
    protocol TappableViewDelegate {
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    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")
       }
    
    }
    
    t表格视图:

     public protocol CustomViewDelegate {
         func update()
         func nonDelegatedMethod()
    }
    
    protocol TappableViewDelegate {
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    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")
       }
    
    }
    
    视图控制器:

     public protocol CustomViewDelegate {
         func update()
         func nonDelegatedMethod()
    }
    
    protocol TappableViewDelegate {
        func tapGestureDetected(gesture:UITapGestureRecognizer)
    }
    
    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")
       }
    
    }
    

    你能发布一个可编译的例子吗?如何声明
    pangestureedetected
    ?我明天将添加它,谢谢Sulthan@AndreaChange Pannable.panGestureDetected(\:)。输入声明panGestureDetected的类的名称,而不是
    Pannable。不管怎样
    只需输入
    YourClass。panGestureDetected(:)
    Leo Dabus:这样做意味着我需要为我拥有的每个tapGestureDetected实现创建一个协议扩展@Sulthan I更新了完整的代码,也可以在这里下载@Andrea,酷!很高兴我能帮忙,我得到了一份工作“使用未解析的标识符“Self”。我的协议没有用public标记。呃,当我们有关联类型要求时,它就不起作用了。这仍然有警报信使:非@objc方法不满足“@objc”协议的可选要求是的,这并不可怕,但比把@objc放在任何地方都好,特别是如果你是“继承”的话来自一系列其他协议及其默认实现。突然间,您就因为该选择器而改变了整个代码库。如何将protocol own函数调用为选择器,我不想在类扩展协议中声明选择器…如果您想在协议扩展本身中提供
    tapGestureDetected
    的默认实现,该怎么办,不在实现协议的具体类中?