'#selector' bezieht sich auf eine Methode, die Objective-C nicht ausgesetzt ist

105

Der neue Xcode 7.3, der den Parameter über addTarget übergibt, funktioniert normalerweise für mich, aber in diesem Fall wird der Fehler im Titel ausgelöst. Irgendwelche Ideen? Es wirft einen anderen, wenn ich versuche, ihn in @objc zu ändern

Danke dir!

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

Der Selektor, den er anruft

func didTapCommentButton(post: Post) {
}
Echizzle
quelle
3
Wie sieht die Klassendeklarationszeile von FeedViewController aus? Wie wird didTapCommentButton deklariert? Welchen Fehler erhalten Sie, wenn Sie @objc hinzufügen?
Vacawama
1
Update, ich habe meinen Beitrag bearbeitet. Ich bin nicht am Computer, der gerade eingeschaltet ist, daher vergesse ich die genaue Fehlermeldung, aber es war eine dieser Situationen, in denen XCode mich auffordert, sie hinzuzufügen, und dann einen Fehler bei seiner eigenen Entscheidung auslöst.
Echizzle
2
Erklärt Ihre Klasse @objcoder ist es eine Unterklasse von NSObject?
NRitH
2
Können Sie versuchen, die Klammern zu entfernen? Es ist ungewöhnlich, wenn man bedenkt, dass man eine Funktion in einem Selektor nicht aufrufen sollte.
DanielEdrisian
Dies löste mein Problem in einem zweiten http://stackoverflow.com/a/36963058/1685165
Darko

Antworten:

173

In meinem Fall war die Funktion des Selektors private. Sobald ich privateden Fehler entfernt hatte, war er verschwunden. Gleiches gilt für fileprivate.

In Swift 4 müssen
Sie @objcder Funktionsdeklaration hinzufügen . Bis schnell 4 wurde dies implizit abgeleitet.

Shaked Sayag
quelle
2
Neben fileprivate.
hstdt
großer Fang @shaked
jbouaziz
@hstdt, also wenn Sie einstellen, fileprivatewird es gelöst?
Hemang
2
@Hemang, nein, @hstdt bedeutet, dass weder privatenoch fileprivatenoch funktionieren wird
Gobe
Es ist besser, die Funktion dynamisch zu gestalten, als private / fileprivate zu entfernen.
Boon
57

Sie müssen das verwenden @objcAttribut auf , didTapCommentButton(_:)es zu benutzen mit #selector.

Sie sagen, Sie haben das getan, aber Sie haben einen weiteren Fehler erhalten. Ich vermute, dass der neue Fehler darin besteht, dass Postes sich nicht um einen Typ handelt, der mit Objective-C kompatibel ist. Sie können eine Methode nur dann für Objective-C verfügbar machen, wenn alle Argumenttypen und der Rückgabetyp mit Objective-C kompatibel sind.

Sie könnten das beheben, indem Sie Posteine Unterklasse aus erstellen NSObject, aber das spielt keine Rolle, da das Argument dafür sowieso didTapCommentButton(_:)kein sein Postwird. Das Argument für eine Aktionsfunktion ist der Absender der Aktion, und dieser Absender wird sein commentButton, was vermutlich a ist UIButton. Sie sollten didTapCommentButtonwie folgt deklarieren :

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

Sie haben dann das Problem, die Postentsprechende Schaltfläche zu erhalten. Es gibt mehrere Möglichkeiten, um es zu bekommen. Hier ist eine.

Ich erfahre (da Ihr Code sagt cell.commentButton), dass Sie eine Tabellenansicht (oder eine Sammlungsansicht) einrichten. Und da Ihre Zelle eine nicht standardmäßige Eigenschaft mit dem Namen hat commentButton, gehe ich davon aus, dass es sich um eine benutzerdefinierte UITableViewCellUnterklasse handelt. Nehmen wir also an, Ihre Zelle ist PostCellwie folgt deklariert:

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

    // other stuff...
}

Dann können Sie die Ansichtshierarchie über die Schaltfläche nach oben gehen, um die zu finden PostCell, und den Beitrag daraus abrufen:

@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
}
Rob Mayoff
quelle
Wenn ich es mit globaler Funktion verwenden möchte? @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
TomSawyer
Sie können es nicht mit einer globalen Funktion verwenden.
Rob Mayoff
8

Versuchen Sie, den Selektor auf eine Wrapper-Funktion zu verweisen, die wiederum Ihre Delegatenfunktion aufruft. Das hat bei mir funktioniert.

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

- -

func wrapperForDidTapCommentButton(post: Post) {
     FeedViewController.didTapCommentButton(post)
}
pfj
quelle
1
Hat für mich gearbeitet! Ich bin mir immer noch nicht sicher, warum das notwendig ist, aber ich werde es nehmen!
Paul Lehn
0

Wie Sie wissen, sagt selector[About] , dass die Objective-CLaufzeit verwendet werden sollte. Deklarationen, die standardmäßig als Objective-C-Laufzeit gekennzeichnet sind privateoder fileprivatenicht . Deshalb haben Sie zwei Varianten:

  1. Markieren Sie Ihre privateoder fileprivateErklärung mit @objc[Über]
  2. Verwenden Sie internal, public, openZugriffsmodifikator [Über]
yoAlex5
quelle