【问题标题】:Argument of '#selector' does not refer to an '@objc' method, property, or initializer'#selector' 的参数不引用 '@objc' 方法、属性或初始化程序
【发布时间】:2017-05-21 14:04:30
【问题描述】:

我在 Swift 3 中子类化了一个用 Objective-C 编写的 UIButton 子类。

当我尝试添加目标时,它会失败并显示错误代码:

class ActionButton: JTImageButton {

    func action() {

    }

    func configure()) {
        // ...
        self.addTarget(self, action: #selector(self.action()), for: .touchUpInside)
        // error: 
        // Argument of '#selector' does not refer to an '@objc' method, property, or initializer

    }
}

【问题讨论】:

标签: ios objective-c swift cocoa-touch


【解决方案1】:

问题是在#selector(self.action()) 中,self.action() 是一个方法调用。您不想调用该方法;你想命名这个方法。改用#selector(action):去掉括号,而且不需要self

【讨论】:

  • 另外与UIViewaction(for:, forKey:)方法冲突。 #selector(action) 将给出“模棱两可的用法”,您的问答stackoverflow.com/questions/35658334/… 适用。
  • 所以func action() { } 必须替换为@matt 所说的其他名称,否则您最终会出现Ambiguous use of action() 错误。
  • 同意。我会在我的回答中指出这一点。我是在回答问题的意图,而不是技术问题。我不应该那样做!
  • 如果函数有多个参数怎么办?
  • @Let.Simoo #selector 表达式中没有参数。您是在描述方法,而不是调用它。
【解决方案2】:

您所要做的就是将函数标记为@objc,并且不需要self 引用或括号

class ActionButton: JTImageButton {

    @objc func btnAction() {

    }

    func configure() {
        // ...
        self.addTarget(self, action: #selector(btnAction), for: .touchUpInside)
        // error: 
        // Argument of '#selector' does not refer to an '@objc' method, property, or initializer

    }
}

如果你愿意,你甚至可以private

【讨论】:

  • 谢谢,但是当我实施你的方法时它说Ambiguous use of 'action'?编辑:将 action() 重命名为 action2() 有帮助。
  • 很奇怪。我将方法重命名为btnAction,它没有给我那个错误。也许与函数名称有关,action?我已经更新了我的答案以表明我的意思
  • 您不需要@objc,因为该类已经继承自 NSObject。
  • 是的。因为它是NSObject 上的公共方法,所以不需要@objc。如果要制作函数private,则需要
【解决方案3】:

在前面添加@objc关键字是完美的方法,但我仍然得到这个错误。 最后,我找到了解决方案如下

方法后面有一对多余的括号,如上图所示。我应该做的是删除它并且效果很好。

【讨论】:

  • 这不能满足问题的需要。另外,请不要转发答案。
  • 这是我遇到的答案,可能有人也会遇到。我通过删除括号解决了它。为什么你对我的回答投了反对票?这是真实的答案! @paper1111
【解决方案4】:

从 cmets 在另一个答案中添加:func action() 不仅是函数名称和操作的糟糕选择,而且无法构建。 (不过,您可以将它用作输入函数参数,为了清楚起见,我在将目标/动作传递给设置这些东西的 init() 时这样做。)我将其替换为 MyAction()为了清楚起见。


试试这个:

self.addTarget(self, action: #selector(MyAction), for: .touchUpInside)

也就是说,一个更好的设计是将 MyAction() 函数移动到按钮超级视图,因为这使得事情更符合基本的 MVC 设计:

监督:

let myButton = ActionButton()
// include other button setup here
myButton.addTarget(self, action: #selector(MyAction), for: .touchUpInside

func action(_ sender: ActionButton) {
    // code against button tap here
}

对此的替代编码,将“action()”方法保留在视图控制器中,但将“addTarget”移动到按钮中:

self.addTarget(superview?, action(superview?.MyAction), for: .touchUpInside)

为什么我要求您考虑将“MyAction()”方法移至超级视图?双重:

  • 它不仅控制按钮,还控制其视图中的所有其他子视图,它们通常通过视图控制器相互交互。
  • 它使按钮在其他场景中的可重用性更高。

【讨论】:

    【解决方案5】:

    不要说self.action(),而是使用ActionButton.action()

    【讨论】:

      【解决方案6】:

      如果你不介意添加一个额外的函数,你可以嵌套这个函数。

      self.addTarget(self, action: myAction, for: UIControlledEvent)
      
      myAction(){
          @obj.methodYouWantToCall(//parameters//)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多