添加 UIButton 目标时“类名没有成员函数名”

Posted

技术标签:

【中文标题】添加 UIButton 目标时“类名没有成员函数名”【英文标题】:"classname has no member functionname" when adding UIButton target 【发布时间】:2016-07-30 11:11:37 【问题描述】:

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

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

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

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

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% 确定该函数存在于类中,并且命名正确。 Full source

我有什么明显的遗漏吗?

我尝试了什么:

根据 this answer 将 @objc 添加到类定义中(但这对于仅 Swift 的东西来说似乎奇怪,不是吗?)

明确地将ratingButtonTapped() 设为public(但这看起来没有必要)

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

【问题讨论】:

啊哈! XCode 的自动提示功能回答了这个问题:我现在需要使用RatingControl.ratingButtonTapped,不带括号。这工作正常并且现在可以编译。我可以删除这个问题 - 但如果有人想提供更详细的答案以及为什么会发生这种情况,我们也许可以将其作为未来读者遇到相同问题的有用资源? 我认为这个问题只要标记为swift3 就可以了,因为一旦 Swift 3 成为标准,这可能会引起一些混乱。关于选择器的一个提示:如果方法与调用者在同一范围内,您可以调用self.methodName 而不是ClassName.methodName,不过只是一个装饰细节。 【参考方案1】:

在 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)

【讨论】:

如果函数没有任何参数并且发生这种情况怎么办? @kashish,不清楚您的问题是什么。最好开始你自己的线程,你会得到或被引导到更合适的答案。【参考方案2】:

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

如果您将函数声明为:

func ratingButtonTapped(_ button: AnyObject) 
    print("Button pressed ?")

您也可以使用它作为您的选择器:

#selector(RatingControl.ratingButtonTapped(button:))

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

您的代码可能在 Swift 中,但是当您为 Cocoa Touch(iOS 框架)编码时,您正在与 Objective-C 运行时进行交互。 selector 是一个需要对 Objective-C 运行时可见的函数。大多数情况下,您都可以免费获得它,因为您在一个最终继承自NSObject 的类中实现它(例如UIViewController)。如果您有一个不继承自 NSObject 的纯 Swift 类,那么您可以添加 @objc 以使该类和方法对 Objective-C 运行时可见。

【讨论】:

【参考方案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,它可以是函数。有些人在操作上使用 @objc 或 public 任何这些前缀都应该起作用。

查看,如果动作在不同的 Class 或 ViewController 中,则必须将 Class 引用放在目标和动作的选择器中。否则,它将尝试始终在同一个文件中调用该操作,无论它在选择器中是否正确。同样,如果动作在同一个文件中,使用 self 作为目标并在动作的选择器内。

干杯

【讨论】:

【参考方案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!")
  

  // ...


【讨论】:

以上是关于添加 UIButton 目标时“类名没有成员函数名”的主要内容,如果未能解决你的问题,请参考以下文章

将按钮超级视图控制器添加到另一个视图控制器时,UIButton 目标无法识别

在 UITableViewCell 中为 UIButton 添加和删除目标操作

使用didSet将目标添加到UITableViewCell中的UIButton

什么时候按钮(UIButton)的目标不是“自我”?

Swift - 将目标添加到子视图内的 UIButton

以编程方式创建的 UIButton 为目标