Reputation: 3459
The new Xcode 7.3 passing the parameter via addTarget usually works for me but in this case it's throwing the error in the title. Any ideas? It throws another when I try to change it to @objc
Thank you!
cell.commentButton.addTarget(self, action: #selector(FeedViewController.didTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
The selector it's calling
func didTapCommentButton(post: Post) {
}
Upvotes: 110
Views: 67342
Reputation: 34235
As you know selector
[About] says that Objective-C runtime
[About] should be used. Declarations that are marked as private
or fileprivate
are not exposed to the Objective-C runtime by default. That is why you have two variants:
private
or fileprivate
method declaration by @objc
[About]internal
, public
, open
method access modifier[About]Upvotes: 0
Reputation: 5792
In my case the function of the selector was private
. Once I removed the private
the error was gone. Same goes for fileprivate
.
In Swift 4
You will need to add @objc
to the function declaration. Until swift 4 this was implicitly inferred.
Upvotes: 180
Reputation: 187
Try having the selector point to a wrapper function, which in turn calls your delegate function. That worked for me.
cell.commentButton.addTarget(self, action: #selector(wrapperForDidTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
-
func wrapperForDidTapCommentButton(post: Post) {
FeedViewController.didTapCommentButton(post)
}
Upvotes: 8
Reputation: 385600
You need to use the @objc
attribute on didTapCommentButton(_:)
to use it with #selector
.
You say you did that but you got another error. My guess is that the new error is that Post
is not a type that is compatible with Objective-C. You can only expose a method to Objective-C if all of its argument types, and its return type, are compatible with Objective-C.
You could fix that by making Post
a subclass of NSObject
, but that's not going to matter, because the argument to didTapCommentButton(_:)
will not be a Post
anyway. The argument to an action function is the sender of the action, and that sender will be commentButton
, which is presumably a UIButton
. You should declare didTapCommentButton
like this:
@objc func didTapCommentButton(sender: UIButton) {
// ...
}
You'll then face the problem of getting the Post
corresponding to the tapped button. There are multiple ways to get it. Here's one.
I gather (since your code says cell.commentButton
) that you're setting up a table view (or a collection view). And since your cell has a non-standard property named commentButton
, I assume it's a custom UITableViewCell
subclass. So let's assume your cell is a PostCell
declared like this:
class PostCell: UITableViewCell {
@IBOutlet var commentButton: UIButton?
var post: Post?
// other stuff...
}
Then you can walk up the view hierarchy from the button to find the PostCell
, and get the post from it:
@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
}
Upvotes: 59