2016-07-30 13 views
15

Super Newb in Swift und iOS-Entwicklung hier."Klassenname hat keinen Mitgliedsfunktionsname" beim Hinzufügen von UIButton Ziel

Ich folge this tutorial über die Implementierung eines benutzerdefinierten Steuerelements in einer Einzelansicht iOS App. Es ist ein Swift 2-Tutorial, aber bis jetzt mache ich OK alles auf 3 zu transponieren, während ich gehe (ich benutze XCode 8 Beta).

Ich habe eine benutzerdefinierte Klasse, RatingControl, verbunden mit einem View im Storyboard.

In der Konstruktor der Klasse, erstelle ich eine Taste:

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 
button.backgroundColor = UIColor.red() 

Dann versuche ich, eine Aktion der Taste zuweisen. Das Tutorial sagt, ich sollte es tun, wie so:

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), 
for: .touchDown)  

und dann erstellen, in der gleichen RatingControl Klasse, wobei das Verfahren:

func ratingButtonTapped(button: UIButton) { 
    print("Button pressed ") 
} 

Aber wenn ich kompilieren, es klagt:

Typ "RatingControl" hat kein Mitglied "ratingButtonTapped"

ich habe 100% sicher gemacht, dass die Funktion in der Klasse vorhanden und richtig benannt ist. Full source

Gibt es etwas Offensichtliches, das ich vermisse?

Was ich versuchte:

  • Added @objc auf die Klassendefinition gemäß this answer (aber das scheint seltsam für eine Swift-only Sache, nicht wahr?)

  • Hergestellt ratingButtonTapped() ausdrücklich public (aber das sieht nicht so aus, als müsste es notwendig sein)

  • Mit Saiten statt Selektor herumgespielt s, button.addTarget(self, action: "RatingControl.ratingButtonTapped", for: .touchDown) und viele mehr, aber das stürzt später einfach ab.

+3

A-ha! XCodes Auto-Hinting-Feature beantwortet die Frage: Ich brauche jetzt 'RatingControl.ratingButtonTapped' ohne Klammern. Das funktioniert gut und kompiliert jetzt. Ich könnte diese Frage löschen - aber wenn jemand eine Antwort geben möchte, die dies genauer erklärt, und * warum * es passiert, könnten wir es vielleicht zu einer nützlichen Quelle für zukünftige Leser machen, die das gleiche Problem haben? –

+2

Ich denke, die Frage ist in Ordnung, solange sie mit 'swift3' gekennzeichnet ist, da dies wahrscheinlich zu einiger Verwirrung führen wird, sobald Swift 3 zum Standard wird. Ein Tipp zu Selektoren: Wenn sich die Methode im selben Bereich wie der Aufrufer befindet, können Sie 'self.methodName' anstelle von' ClassName.methodName' aufrufen, nur ein kosmetisches Detail. – xoudini

+0

@xoudini danke! –

Antwort

11

Dies geschah, weil Swift 3 die Art und Weise verändert hat er die ersten Parameternamen behandelt. In Swift 3 müssen beim Aufruf einer Funktion alle Parameternamen verwendet werden, es sei denn, ein expliziter _ wurde als Parametername deklariert.

Was Sie verwendet als Wähler war in Ordnung, wenn Sie Ihre Funktion als erklärt hatte:

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

Sie auch diese als Selektor verwendet haben könnte:

#selector(RatingControl.ratingButtonTapped(button:)) 

Added @objc zu der Klassendefinition nach dieser Antwort (aber das scheint seltsam für eine Swift-only Sache, nein?)

Ihr Code in Swift sein kann, aber Sie interagieren mit der Objective-C-Laufzeit, wenn Sie Codierung für Cocoa Touch (iOS-Framework). Der Selektor ist eine Funktion, die für die Objective-C-Laufzeit sichtbar sein muss. Sie erhalten dies die meiste Zeit kostenlos, da Sie dies in einer Klasse implementieren, die letztlich von NSObject (wie UIViewController) erbt. Wenn Sie eine Nur-Swift-Klasse haben, die nicht von NSObject erbt, können Sie @objc hinzufügen, um die Klasse und Methoden für die Objective-C-Laufzeit sichtbar zu machen.

15

In Swift 3, Methodenreferenz für: func ratingButtonTapped(button: UIButton) wird ratingButtonTapped(button:).

Also, mit #selector(RatingControl.ratingButtonTapped(button:)) auch arbeiten.

Und wenn Sie #selector(RatingControl.ratingButtonTapped(_:)) behalten wollen, dann müssen Sie die ratingButtonTapped Methode als erklären:

func ratingButtonTapped(_ button: UIButton) { //<- `_` 
    print("Button pressed ") 
} 

Und wenn Sie nur eine ratingButtonTapped Methode in der Klasse haben, können Sie den Wähler ansprechen als #selector(RatingControl.ratingButtonTapped) oder einfach (von innen RatingControl Klasse) #selector(ratingButtonTapped).

+0

einfach nur gute Antwort, danke – manukv

+0

Was, wenn die Funktion keine Argumente hat und dies geschieht? – kashish

+0

@kashish, es ist nicht klar, was Ihr Problem ist. Starten Sie lieber Ihren eigenen Thread und Sie erhalten oder werden zu geeigneteren Antworten geführt. – OOPer

3

Wenn Sie eine Aktion aus einer anderen Klasse in Ihrem View Controller aufrufen möchten, können Sie dies versuchen.

Verwenden Sie ViewController() für Ihr Ziel. Verwenden Sie ViewController.functionName für Ihren Selektor. Verwenden Sie keine Hilfsmethode für die View-Controller-Variable wie "vc", sonst können Sie nicht auf Objekte innerhalb des ViewControllers zugreifen.

Hier ist ein Beispiel Ziel:

self.addTarget(ViewController(), action:#selector(ViewController.Test(_:)), for: UIControlEvents.touchDragInside) 

In Ihrem View-Controller, hier ist ein Beispiel Aktion

@IBAction func Test(_ sender: Any?) { 
    print("Goodtime was here") 

}

Im Ziel Sie() in hinzufügen muss aber nicht die Auswahl der Aktion. Sie müssen @IBAction nicht aufrufen, es kann nur funktionieren. Manche Leute verwenden @objc oder public, wenn eines dieser Präfixe auf der Aktion funktioniert.

Wenn die Aktion in einer anderen Klasse oder ViewController ausgeführt wird, müssen Sie die Klassenreferenz sowohl im Ziel als auch in der Auswahl der Aktion angeben. Andernfalls wird versucht, die Aktion immer in derselben Datei aufzurufen, unabhängig davon, ob sie in der Auswahl korrekt ist.Wenn sich die Aktion in der gleichen Datei befindet, verwenden Sie self für das Ziel und im Selektor der Aktion.

Prost

2

Wenn er erstmals in schnellen 3-Tasten-Ziele Hinzufügen müssen Sie in class sein.

class SomeClass { 

    // ... 

    let button = UIButton() 
    // configure button to taste... 

    button.addTarget(self, 
        action: #selector(doSomething), 
        for: .touchUpInside) 

    // ... 

    @objc public func doSomething() { 
    print("hello, world!") 
    } 

    // ... 

} 
Verwandte Themen