“ #selector”是指未公开给Objective-C的方法


105

新的Xcode 7.3通过addTarget传递参数通常对我有用,但是在这种情况下,它会在标题中引发错误。有任何想法吗?当我尝试将其更改为@objc时,它将引发另一个

谢谢!

cell.commentButton.addTarget(self, action: #selector(FeedViewController.didTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

它正在调用的选择器

func didTapCommentButton(post: Post) {
}

3
FeedViewController的类声明行是什么样的?TapCommentButton是如何声明的?添加@objc会遇到什么错误?
vacawama

1
更新,我编辑了我的帖子。我现在不在电脑上了,所以我忘记了确切的错误消息,但这是XCode告诉我添加它,然后根据自己的决定抛出错误的情况之一。
Echizzle '16

2
是您的类声明了@objc还是它的子类NSObject
NRitH '16

2
您可以尝试删除括号吗?考虑到您不应该在选择器中调用函数,这是不寻常的。
DanielEdrisian

Answers:


173

就我而言,选择器的功能是private。一旦我删除private错误消失了。同样适用fileprivate

在Swift 4中,
您将需要添加@objc到函数声明中。直到快速4,这是隐式推断。


2
除了fileprivate
hstdt

@shaked很棒的收获
jbouaziz

@hstdt,所以如果您设置了,fileprivate它将解决吗?
Hemang '17年

2
@Hemang,不,@ hstdt表示既不起作用,privatefileprivate不起作用
Gobe

使功能具有动态性比删除private / fileprivate更合适。
Boon

57

您需要使用将该@objc属性与didTapCommentButton(_:)一起使用#selector

您说您这样做了,但又遇到另一个错误。我的猜测是,新错误是Post与Objective-C不兼容的类型。仅当方法的所有参数类型及其返回类型均与Objective-C兼容时,才可以将方法公开给Objective-C。

您可以通过创建Post的子类来解决此问题NSObject,但这并不重要,因为to的参数无论如何didTapCommentButton(_:)都不会Post。动作函数的参数是动作的发送者,而该发送者将是commentButton,大概是a UIButton。您应该这样声明didTapCommentButton

@objc func didTapCommentButton(sender: UIButton) {
    // ...
}

然后,您将面临获取Post与所点击按钮相对应的问题。有多种获取方法。这是一个

我收集到(因为您的代码说了cell.commentButton),您正在设置一个表视图(或一个集合视图)。并且由于您的单元格具有一个名为的非标准属性commentButton,因此我假设它是一个自定义UITableViewCell子类。因此,假设您的单元格是这样PostCell声明的:

class PostCell: UITableViewCell {
    @IBOutlet var commentButton: UIButton?
    var post: Post?

    // other stuff...
}

然后,您可以从按钮开始沿视图层次结构查找PostCell,并从中获取帖子:

@objc func didTapCommentButton(sender: UIButton) {
    var ancestor = sender.superview
    while ancestor != nil && !(ancestor! is PostCell) {
        ancestor = view.superview
    }
    guard let cell = ancestor as? PostCell,
        post = cell.post
        else { return }

    // Do something with post here
}

如果我想将其与全局功能一起使用?@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
TomSawyer

您不能将其与全局函数一起使用。
rob mayoff

8

尝试使选择器指向包装函数,包装函数依次调用您的委托函数。那对我有用。

cell.commentButton.addTarget(self, action: #selector(wrapperForDidTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

--

func wrapperForDidTapCommentButton(post: Post) {
     FeedViewController.didTapCommentButton(post)
}

1
为我工作!仍然不确定为什么要这样做,但我会接受!
Paul Lehn

0

如您所知selector[About]Objective-C应该使用运行时。默认情况下,标记为private或未fileprivate公开给Objective-C运行时的声明。这就是为什么您有两个变体的原因:

  1. [关于]上标记您privatefileprivate声明@objc
  2. 使用internalpublicopen访问修饰符[关于]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.