110 votes

#selector' fait référence à une méthode qui n'est pas exposée à l'Objective-C.

Le nouveau Xcode 7.3 qui passe le paramètre via addTarget fonctionne généralement pour moi, mais dans ce cas, il envoie l'erreur dans le titre. Une idée ? Une autre erreur survient lorsque j'essaie de le changer en @objc.

Merci !

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

Le sélecteur qu'il appelle

func didTapCommentButton(post: Post) {
}

3 votes

À quoi ressemble la ligne de déclaration de classe de FeedViewController ? Comment est déclaré didTapCommentButton ? Quelle erreur obtenez-vous lorsque vous ajoutez @objc ?

1 votes

Mise à jour, j'ai modifié mon message. Je suis loin de l'ordinateur sur lequel il est installé en ce moment et j'ai oublié le message d'erreur exact, mais il s'agissait d'une de ces situations où XCode me dit de l'ajouter puis lance une erreur de sa propre décision.

2 votes

Votre classe déclare-t-elle @objc ou est-ce une sous-classe de NSObject ?

179voto

Shaked Sayag Points 3246

Dans mon cas, la fonction du sélecteur était la suivante private . Une fois que j'ai retiré le private l'erreur a disparu. Il en va de même pour fileprivate .

En Swift 4
Vous devrez ajouter @objc à la déclaration de la fonction. Jusqu'à swift 4, cela était implicitement déduit.

2 votes

En plus de fileprivate .

0 votes

Belle prise @shaked

0 votes

@hstdt, donc si vous mettez, fileprivate sera-t-il résolu ?

59voto

rob mayoff Points 124153

Vous devez utiliser le @objc l'attribut didTapCommentButton(_:) pour l'utiliser avec #selector .

Vous dites que vous l'avez fait mais que vous avez eu une autre erreur. A mon avis, la nouvelle erreur est que Post n'est pas un type qui est compatible avec l'Objective-C. Vous ne pouvez exposer une méthode à l'Objective-C que si tous ses types d'arguments, ainsi que son type de retour, sont compatibles avec l'Objective-C.

Vous pouvez corriger cela en faisant Post une sous-classe de NSObject mais ça n'a pas d'importance, parce que l'argument pour didTapCommentButton(_:) ne sera pas un Post de toute façon. L'argument d'une fonction d'action est le expéditeur de l'action, et cet expéditeur sera commentButton qui est vraisemblablement un UIButton . Vous devez déclarer didTapCommentButton comme ça :

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

Vous serez alors confronté au problème de l'obtention de la Post correspondant à la touche touchée. Il y a plusieurs façons de l'obtenir. En voici une.

Je suppose (puisque votre code dit cell.commentButton ) que vous êtes en train de configurer une vue de table (ou une vue de collection). Et puisque votre cellule possède une propriété non standard nommée commentButton je suppose que c'est une coutume UITableViewCell sous-classe. Donc, supposons que votre cellule est un PostCell déclaré comme ça :

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

    // other stuff...
}

Ensuite, vous pouvez remonter la hiérarchie des vues à partir du bouton pour trouver le bouton PostCell et d'en tirer le message :

@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
}

0 votes

Si je veux l'utiliser avec une fonction globale ? @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes

0 votes

Vous ne pouvez pas l'utiliser avec une fonction globale.

8voto

pfj Points 189

Essayez de faire en sorte que le sélecteur pointe vers une fonction wrapper, qui appelle à son tour votre fonction déléguée. Cela a fonctionné pour moi.

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

-

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

1 votes

Cela a marché pour moi ! Je ne sais toujours pas pourquoi c'est nécessaire mais je le prends !

0voto

yoAlex5 Points 2350

Comme vous le savez selector [À propos] dit que Objective-C runtime [À propos] doivent être utilisées. Les déclarations qui sont marquées comme private o fileprivate ne sont pas exposés au runtime Objective-C par défaut . C'est pourquoi vous avez deux variantes :

  1. Marquez votre private o fileprivate déclaration de méthode par @objc [À propos]
  2. Utilisez internal , public , open modificateur d'accès à la méthode [À propos]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X