Swift:使用协议扩展导致“无法识别的选择器发送到实例” [英] Swift: Using protocol extension results in "unrecognized selector sent to instance"

查看:90
本文介绍了Swift:使用协议扩展导致“无法识别的选择器发送到实例”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为所有UIViewControllers添加一个on-tap功能,它们符合协议 MyProtocol

I'm trying to add a on-tap functionality to all UIViewControllers where they conform to protocol MyProtocol.

以下是我的表现:

import UIKit

protocol MyProtocol: class{
    var foo: String? {get set}
    func bar()
}


extension MyProtocol where Self: UIViewController {
    func bar() {
        print(foo)
    }
}


class TestViewController: UIViewController, MyProtocol{
    var foo: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        foo = "testing"
        let tapGesture = UITapGestureRecognizer(target: self, action: "bar")
}

当点击屏幕时会导致以下结果:

Which results in following when screen is tapped:

由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:无法识别的选择器发送到实例

我理解错误,但不知道如何修复它。任何人都可以建议如何做到这一点?

I understand the error but don't know how to fix it. Can anyone suggest how this can be done?

推荐答案

问题在于Objective-C对协议扩展一无所知。因此,您不能使用协议扩展将方法注入到类中,以便Objective-C的消息传递机制可以看到它。您需要在视图控制器类本身中声明 bar

The problem is that Objective-C knows nothing of protocol extensions. Thus, you cannot use a protocol extension to inject a method into a class in such a way that Objective-C's messaging mechanism can see it. You need to declare bar in the view controller class itself.

(我意识到这正是你试图避免做的事情,但我无能为力。)

(I realize that this is precisely what you were trying to avoid doing, but I can't help that.)

一种解决方法可能就是这样:

A sort of workaround might be this:

override func viewDidLoad() {
    super.viewDidLoad()

    foo = "testing"
    let tapGesture = UITapGestureRecognizer(target: self, action: "baz")
    self.view.addGestureRecognizer(tapGesture)
}

func baz() {
    self.bar()
}

我们现在使用Objective-C的消息传递机制来调用 baz 然后使用Swift的消息传递机制来调用 bar ,当然这样可行。我意识到它并不像你想象的那么干净,但至少现在 bar 的实现可以存在于协议扩展中。

We are now using Objective-C's messaging mechanism to call baz and then Swift's messaging mechanism to call bar, and of course that works. I realize it isn't as clean as what you had in mind, but at least now the implementation of bar can live in the protocol extension.

(当然,另一种解决方案是在协议扩展存在之前完成我们所做的事情:让所有视图控制器继承自包含 bar的一些常见自定义UIViewController子类。)

(Of course, another solution would be to do what we did before protocol extensions existed: make all your view controllers inherit from some common custom UIViewController subclass containing bar.)

这篇关于Swift:使用协议扩展导致“无法识别的选择器发送到实例”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆