添加 UIButton 目标时出现“classname has no member functionname”

"classname has no member functionname" when adding UIButton target

提问人:Pekka 提问时间:7/30/2016 最后编辑:CommunityPekka 更新时间:4/18/2017 访问量:5517

问:

这里是 Swift 和 iOS 开发的超级新手。

我正在阅读有关在单个视图 iOS 应用程序中实现自定义控件的教程。这是一个 Swift 2 教程,但到目前为止,我还可以将所有内容转换为 3(我使用 XCode 8 Beta)。

我有一个自定义类,连接到情节提要中的一个。RatingControlView

在类的构造函数中,我创建了一个按钮:

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
button.backgroundColor = UIColor.red()

然后,我尝试为按钮分配一个操作。教程说我应该这样做:

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), 
for: .touchDown)       

然后在同一类中创建以下方法:RatingControl

func ratingButtonTapped(button: UIButton) {
  print("Button pressed 👍")
}

但是当我编译时,它抱怨:

类型“RatingControl”没有成员“ratingButtonTapped”

我已经 100% 确定该函数存在,在类中,并且已正确命名。完整来源

我是否遗漏了什么?

我试过什么:

  • 根据这个答案添加到类定义中(但对于仅限 Swift 的东西来说,这似乎很奇怪,不是吗?@objc

  • 明确提出(但看起来没有必要)ratingButtonTapped()public

  • 摆弄字符串而不是选择器等等,但这只会在以后崩溃。button.addTarget(self, action: "RatingControl.ratingButtonTapped", for: .touchDown)

斯威夫特 Swift3

评论

3赞 Pekka 7/30/2016
啊哈!XCode 的自动提示功能回答了这个问题:我现在需要使用,没有括号。这工作正常,现在可以编译了。我可以删除这个问题 - 但如果有人想提供一个答案,更详细地解释这一点以及为什么会发生这种情况,我们也许能够让它成为未来有同样问题的读者的有用资源?RatingControl.ratingButtonTapped
2赞 xoudini 7/30/2016
我认为这个问题只要被标记就可以了,因为一旦 Swift 3 成为标准,这可能会引起一些混乱。不过,关于选择器的一个提示是:如果该方法与调用者在同一范围内,则可以调用而不是 ,但只是一个修饰细节。swift3self.methodNameClassName.methodName

答:

11赞 vacawama 7/30/2016 #1

发生这种情况是因为 Swift 3 改变了它处理第一个参数名称的方式。在 Swift 3 中,调用函数时必须使用所有参数名称,除非将显式声明为参数名称。_

如果您已将函数声明为:

func ratingButtonTapped(_ button: AnyObject) {
    print("Button pressed 👍")
}

您也可以将其用作选择器:

#selector(RatingControl.ratingButtonTapped(button:))

根据此答案将@objc添加到类定义中(但似乎 对于一个只有 Swift 的东西来说很奇怪,不是吗?

您的代码可能使用 Swift,但当您为 Cocoa Touch(iOS 框架)编写代码时,您正在与 Objective-C 运行时进行交互。选择器是一个需要对 Objective-C 运行时可见的函数。大多数时候,您都可以免费获得它,因为您是在最终继承自 (like ) 的类中实现的。如果你有一个仅 Swift 的类,它不继承自 ,那么你可以添加以使类和方法对 Objective-C 运行时可见。NSObjectUIViewControllerNSObject@objc

16赞 OOPer 7/30/2016 #2

在 Swift 3 中,对 的方法引用: 变为 .func ratingButtonTapped(button: UIButton)ratingButtonTapped(button:)

所以,使用也有效。#selector(RatingControl.ratingButtonTapped(button:))

如果要保留,则需要将方法声明为:#selector(RatingControl.ratingButtonTapped(_:))ratingButtonTapped

func ratingButtonTapped(_ button: UIButton) { //<- `_`
    print("Button pressed 👍")
}

如果类中只有一个方法,则可以将选择器称为或简单地(从类内部)。ratingButtonTapped#selector(RatingControl.ratingButtonTapped)RatingControl#selector(ratingButtonTapped)

评论

0赞 kashish 1/19/2018
如果函数没有任何参数并且发生这种情况怎么办?
0赞 OOPer 1/19/2018
@kashish,目前尚不清楚您的问题是什么。最好开始你自己的线程,你会得到或被引导到更合适的答案。
3赞 Goodtime 11/22/2016 #3

如果要从其他类调用视图控制器中的操作,可以尝试此操作。

将 ViewController() 用于目标。将 ViewController.functionName 用于选择器。不要对视图控制器变量使用帮助程序方法,如“vc”,否则您将无法访问 ViewController 中的对象。

下面是一个示例目标:

self.addTarget(ViewController(), action:#selector(ViewController.Test(_:)), for: UIControlEvents.touchDragInside)

在视图控制器中,下面是一个示例操作

@IBAction func Test(_ sender: Any?) {
    print("Goodtime was here")

}

在目标中,必须添加 (),但不能在操作的选择器中添加。您不必调用@IBAction,它可以是func。有些人使用@objc或公共,这些前缀中的任何一个在操作上都应该有效。

查看时,如果操作位于不同的 Class 或 ViewController 中,则必须将 Class 引用放在目标和操作的选择器中。否则,它将尝试始终调用同一文件中的操作,而不管它在选择器中是否正确。同样,如果操作位于同一文件使用中,则 self 用于目标和操作的选择器。

干杯

2赞 Aquila Sagitta 4/18/2017 #4

在 swift 3 中添加按钮目标时,首先需要在 .class

class SomeClass {

  // ...

  let button = UIButton()
  // configure button to taste...

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

  // ...

  @objc public func doSomething() {
    print("hello, world!")
  }

  // ...

}