首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在协议扩展中添加Target-Action失败

在协议扩展中添加Target-Action失败
EN

Stack Overflow用户
提问于 2015-11-25 22:23:33
回答 4查看 1.8K关注 0票数 12

我有一组视图控制器,其中将有一个菜单栏按钮。我创建了一个协议,供这些viewControllers采用。此外,我还对协议进行了扩展,添加了默认功能。

我的协议看起来是这样的

代码语言:javascript
复制
protocol CenterViewControllerProtocol: class {

    var containerDelegate: ContainerViewControllerProtocol? { get set }

    func setupMenuBarButton()
}

并且,扩展看起来是这样的,

代码语言:javascript
复制
extension CenterViewControllerProtocol where Self: UIViewController {

    func setupMenuBarButton() {
        let barButton = UIBarButtonItem(title: "Menu", style: .Done, target: self, action: "menuTapped")
        navigationItem.leftBarButtonItem = barButton
    }

    func menuTapped() {
        containerDelegate?.toggleSideMenu()
    }
}

我的viewController采用的协议是-

代码语言:javascript
复制
class MapViewController: UIViewController, CenterViewControllerProtocol {

    weak var containerDelegate: ContainerViewControllerProtocol?

    override func viewDidLoad() {
        super.viewDidLoad()

        setupMenuBarButton()
    }
}

我得到了一个可以很好地显示的按钮,但当我点击它时,应用程序崩溃了,

代码语言:javascript
复制
[AppName.MapViewController menuTapped]: unrecognized selector sent to instance 0x7fb8fb6ae650

如果我在ViewController中实现该方法,它会工作得很好。但我会在所有符合协议的viewControllers中复制代码。

我做错什么了吗?提前谢谢。

EN

回答 4

Stack Overflow用户

发布于 2015-11-26 13:16:38

目前似乎不支持使用协议扩展。根据fluidsonic's answer here

在任何情况下,您打算通过选择器使用的所有函数都应该标记为dynamic或@objc。如果这导致错误:@objc不能在此上下文中使用,那么您正在尝试做的事情就不受支持。“

在您的示例中,我认为解决这个问题的一种方法是创建一个UIBarButtonItem的子类,每当它被点击时都会调用一个块。然后,您可以在该块中调用containerDelegate?.toggleSideMenu()

票数 0
EN

Stack Overflow用户

发布于 2016-02-02 00:43:13

这在Xcode7.3Beta中也会编译,但也会崩溃,所以最后你应该使用一个丑陋的超类作为操作的目标,我想这是你我都想要避免的。

票数 0
EN

Stack Overflow用户

发布于 2017-03-15 02:57:17

这是一个古老的问题,但我也遇到了同样的问题,并提出了一个可能不完美的解决方案,但这是我能想到的唯一方法。

显然,即使在Swift 3中,也不可能为您的协议扩展设置目标操作。但是,无需在所有符合协议的ViewControllers中实现func menuTapped()方法,也可以实现所需的功能。

首先,让我们向协议中添加新方法

代码语言:javascript
复制
protocol CenterViewControllerProtocol: class {

    var containerDelegate: ContainerViewControllerProtocol? { get set }

    //implemented in extension
    func setupMenuBarButton()
    func menuTapped()

    //must implement in your VC
    func menuTappedInVC()
}

现在像这样更改您的扩展

代码语言:javascript
复制
extension CenterViewControllerProtocol where Self: UIViewController {

        func setupMenuBarButton() {
            let barButton = UIBarButtonItem(title: "Menu", style: .Done, target: self, action: "menuTappedInVC")
            navigationItem.leftBarButtonItem = barButton
        }

        func menuTapped() {
            containerDelegate?.toggleSideMenu()
        }
    }

请注意,现在按钮在扩展中的操作是"menuTappedInVC“,而不是"menuTapped”。并且每个符合CenterViewControllerProtocol的ViewController都必须实现此方法。

在你的ViewController中,

代码语言:javascript
复制
class MapViewController: UIViewController, CenterViewControllerProtocol {

    weak var containerDelegate: ContainerViewControllerProtocol?

    override func viewDidLoad() {
        super.viewDidLoad()

        setupMenuBarButton()
    }

    func menuTappedInVC()
    {
      self.menuTapped()
    }

你所要做的就是在你的VC中实现menuTappedInVC()方法,这就是你的目标动作方法。在此过程中,您可以将该任务委托给已经在您的协议扩展中实现的menuTapped

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33918990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档