it-swarm.com.de

@selector () in Swift?

Ich versuche, in NSTimer ein Swift zu erstellen, aber ich habe einige Probleme.

NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)

test() ist eine Funktion in derselben Klasse.


Ich erhalte eine Fehlermeldung im Editor:

Es konnte keine Überladung für 'init' gefunden werden, die die angegebenen Argumente akzeptiert

Wenn ich selector: test() in selector: nil ändere, verschwindet der Fehler.

Ich habe es versucht:

  • selector: test()
  • selector: test
  • selector: Selector(test())

Aber nichts funktioniert und ich kann keine Lösung in den Referenzen finden.

639
Arbitur

Swift selbst verwendet keine Selektoren - verschiedene Entwurfsmuster, die in Objective-C Selektoren verwenden, funktionieren in Swift unterschiedlich. (Verwenden Sie beispielsweise die optionale Verkettung für Protokolltypen oder is/as -Tests anstelle von _respondsToSelector:_, und verwenden Sie für eine bessere Typ-/Speichersicherheit möglichst Verschlüsse anstelle von _performSelector:_ .)

Es gibt jedoch noch eine Reihe wichtiger ObjC-basierter APIs, die Selektoren verwenden, darunter Timer und das Ziel-/Aktionsmuster. Swift bietet den Typ Selector für die Arbeit mit diesen. (Swift verwendet dies automatisch anstelle des Typs SEL von ObjC.)

In Swift 2.2 (Xcode 7.3) und höher (einschließlich Swift 3/Xcode 8 und Swift 4/Xcode 9):

Sie können ein Selector aus einem Swift Funktionstyp mit dem Ausdruck _#selector_ erstellen.

_let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)
_

Das Tolle an diesem Ansatz? Eine Funktionsreferenz wird vom Swift Compiler geprüft, sodass Sie den Ausdruck _#selector_ nur mit Klassen-/Methodenpaaren verwenden können, die tatsächlich existieren und als Selektoren verwendet werden können (siehe "Verfügbarkeit von Selektoren" weiter unten) ). Es steht Ihnen auch frei, Ihre Funktionsreferenz nur so spezifisch zu machen, wie Sie möchten, wie es die Swift 2.2+ Regeln für die Benennung von Funktionstypen vorschreiben.

(Dies ist tatsächlich eine Verbesserung gegenüber der Anweisung @selector() von ObjC, da bei der Prüfung des Compilers _-Wundeclared-selector_ nur überprüft wird, ob der angegebene Selektor vorhanden ist. Die Funktionsreferenz Swift, die Sie an _#selector_ übergeben, prüft die Existenz und Zugehörigkeit in einer Klasse und Typ Signatur.)

Für die Funktionsreferenzen, die Sie an den Ausdruck _#selector_ übergeben, gelten einige zusätzliche Einschränkungen:

  • Mehrere Funktionen mit demselben Basisnamen können anhand ihrer Parameterbezeichnungen unter Verwendung der oben genannten Syntax für Funktionsreferenzen (z. B. insertSubview(_:at:) vs insertSubview(_:aboveSubview:)) unterschieden werden. Wenn eine Funktion jedoch keine Parameter hat, ist die einzige Möglichkeit, sie zu disambiguieren, die Verwendung eines as -Castings mit der Typensignatur der Funktion (z. B. foo as () -> () vs foo(_:)).
  • Es gibt eine spezielle Syntax für Eigenschafts-Getter/Setter-Paare in Swift 3.0+. Wenn Sie beispielsweise einen _var foo: Int_ angeben, können Sie #selector(getter: MyClass.foo) oder #selector(setter: MyClass.foo) verwenden.

Allgemeine Hinweise:

Fälle, in denen _#selector_ nicht funktioniert, und Benennung: Manchmal haben Sie keine Funktionsreferenz, mit der Sie einen Selektor erstellen können (zum Beispiel mit in der ObjC-Laufzeit dynamisch registrierten Methoden). In diesem Fall können Sie Selector aus einer Zeichenfolge erstellen: z. Selector("dynamicMethod:") - obwohl Sie die Gültigkeitsprüfung des Compilers verlieren. Wenn Sie dies tun, müssen Sie die ObjC-Benennungsregeln befolgen, einschließlich der Doppelpunkte (_:_) für jeden Parameter.

Verfügbarkeit des Selektors: Die vom Selektor referenzierte Methode muss der ObjC-Laufzeit zur Verfügung gestellt werden. In Swift 4 muss jeder Methode, die für ObjC verfügbar gemacht wird, das Attribut _@objc_ vorangestellt werden. (In früheren Versionen war dieses Attribut in einigen Fällen kostenlos, aber jetzt müssen Sie es explizit deklarieren.)

Denken Sie daran, dass private Symbole auch nicht zur Laufzeit verfügbar sind - Ihre Methode muss mindestens internal sichtbar sein.

Schlüsselpfade: Diese beziehen sich auf Selektoren, sind jedoch nicht mit diesen identisch. Auch für diese Befehle gibt es in Swift 3 eine spezielle Syntax: z. chris.valueForKeyPath(#keyPath(Person.friends.firstName)). Siehe SE-0062 für Details. Und noch mehr KeyPath -Inhalte in Swift 4 . Verwenden Sie also gegebenenfalls die richtige KeyPath-basierte API anstelle von Selektoren.

Weitere Informationen zu Selektoren finden Sie unter Interaktion mit Objective-C-APIs in Using Swift with Cocoa and Objective-C .

Hinweis: Vor Swift 2.2 stimmte Selector mit StringLiteralConvertible überein, sodass Sie möglicherweise alten Code dort finden, wo Bloße Zeichenfolgen werden an APIs übergeben, die Selektoren verwenden. Sie sollten "Convert to Current Swift Syntax" in Xcode ausführen, um diejenigen zu ermitteln, die _#selector_ verwenden.

915
rickster

Hier ist ein kurzes Beispiel für die Verwendung der Selector -Klasse in Swift:

override func viewDidLoad() {
    super.viewDidLoad()

    var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
    self.navigationItem.rightBarButtonItem = rightButton
}

func method() {
    // Something cool here   
}

Beachten Sie, dass die als Zeichenfolge übergebene Methode zur Laufzeit fehlschlägt, nicht kompiliert und Ihre App abstürzt, wenn sie nicht funktioniert. Achtung

83
Oscar Swanros

Wenn Ihre (schnelle) Klasse nicht von einer Objective-C-Klasse abstammt, muss am Ende der Zeichenfolge des Zielmethodennamens ein Doppelpunkt stehen, und Sie müssen die Eigenschaft @objc mit Ihrer Zielmethode verwenden, z.

var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))

@objc func method() {
    // Something cool here   
} 

andernfalls wird zur Laufzeit der Fehler "Unbekannter Selektor" angezeigt.

46
user3771857

Swift 2.2+ und Swift 3 Update

Verwenden Sie den neuen Ausdruck #selector, der die Verwendung von String-Literalen überflüssig macht und die Verwendung weniger fehleranfällig macht. Als Referenz:

Selector("keyboardDidHide:")

wird

#selector(keyboardDidHide(_:))

Siehe auch: Swift Evolution Proposal

Hinweis (Swift 4.0):

Wenn Sie #selector verwenden, müssen Sie die Funktion als @objc markieren.

Beispiel:

@objc func something(_ sender: UIButton)

31
Kyle Clegg

Für zukünftige Leser stellte ich fest, dass ich ein Problem hatte und ein unrecognised selector sent to instance erhielt. Fehler, der durch das Markieren des Ziels func als privat verursacht wurde.

Das funcMUSS öffentlich sichtbar sein, um von einem Objekt mit einem Verweis auf einen Selektor aufgerufen zu werden.

23
Rob Sanders

Swift 4.

sie erstellen den Selektor wie unten.

1.Füge das Event zu einem Button hinzu wie:

button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside)

und die Funktion wird wie folgt sein:

@objc func clickedButton(sender: AnyObject) {

}
21
pravin salame

Nur für den Fall, dass jemand anderes das gleiche Problem mit NSTimer hat, bei dem keine der anderen Antworten das Problem behoben hat, ist es wirklich wichtig zu erwähnen, dass, wenn Sie eine Klasse verwenden, die weder direkt noch tief in der Hierarchie von NSObject erbt ( zB manuell erstellte Swift -Dateien), keine der anderen Antworten funktioniert, auch wenn wie folgt angegeben:

let timer = NSTimer(timeInterval: 1, target: self, selector: "test", 
                    userInfo: nil, repeats: false)
func test () {}

Ohne etwas anderes zu ändern, als nur die Klasse von NSObject erben zu lassen, wurde der Fehler "Unbekannter Selektor" nicht mehr angezeigt und meine Logik funktionierte wie erwartet.

19
Martin Cazares

Wenn Sie einen Parameter vom NSTimer an die Funktion übergeben möchten, ist dies Ihre Lösung:

var somethingToPass = "It worked"

let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false)

func tester(timer: NSTimer)
{
    let theStringToPrint = timer.userInfo as String
    println(theStringToPrint)
}

Fügen Sie den Doppelpunkt in den Auswahltext (Tester :) ein, und Ihre Parameter gehen in userInfo.

Ihre Funktion sollte NSTimer als Parameter verwenden. Dann extrahieren Sie einfach userInfo, um den übergebenen Parameter zu erhalten.

14
Scooter

Selektoren sind eine interne Darstellung eines Methodennamens in Objective-C. In Objective-C würde "@selector (methodName)" eine Quellcodemethode in einen Datentyp von SEL konvertieren. Da Sie die @selector-Syntax in Swift nicht verwenden können (Rickster ist dort an der richtigen Stelle), müssen Sie den Methodennamen direkt als String-Objekt oder durch Übergabe eines String-Objekts an den Selector-Typ manuell angeben . Hier ist ein Beispiel:

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:"logout"
)

oder

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)
10
Jon Tsiros

Swift 4.1
Mit Probe der Tippgeste

let gestureRecognizer = UITapGestureRecognizer()
self.view.addGestureRecognizer(gestureRecognizer)
gestureRecognizer.addTarget(self, action: #selector(self.dismiss(completion:)))

// Use destination 'Class Name' directly, if you selector (function) is not in same class.
//gestureRecognizer.addTarget(self, action: #selector(DestinationClass.dismiss(completion:)))


@objc func dismiss(completion: (() -> Void)?) {
      self.dismiss(animated: true, completion: completion)
}

In Apples Dokument finden Sie weitere Informationen zu: Selector Expression

8
Krunal
// for Swift 2.2
// version 1
buttton.addTarget(self, action: #selector(ViewController.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(ViewController.tappedButton2(_:)), forControlEvents: .TouchUpInside)

// version 2
buttton.addTarget(self, action: #selector(self.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(self.tappedButton2(_:)), forControlEvents: .TouchUpInside)

// version 3
buttton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(tappedButton2(_:)), forControlEvents: .TouchUpInside)

func tappedButton() {
  print("tapped")
}

func tappedButton2(sender: UIButton) {
  print("tapped 2")
}

// Swift 3.x
button.addTarget(self, action: #selector(tappedButton(_:)), for: .touchUpInside)

func tappedButton(_ sender: UIButton) {
  // tapped
}

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

func tappedButton(_ sender: UIButton, _ event: UIEvent) {
  // tapped
}
6
John Lee
Create Refresh control using Selector method.   
    var refreshCntrl : UIRefreshControl!
    refreshCntrl = UIRefreshControl()
    refreshCntrl.tintColor = UIColor.whiteColor()
    refreshCntrl.attributedTitle = NSAttributedString(string: "Please Wait...")
    refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged)
    atableView.addSubview(refreshCntrl)

// Steuerungsmethode aktualisieren

func refreshControlValueChanged(){
    atableView.reloadData()
    refreshCntrl.endRefreshing()

}
5

Da Swift 3.0 veröffentlicht wird, ist es noch etwas subtiler, eine targetAction als geeignet zu deklarieren

class MyCustomView : UIView {

    func addTapGestureRecognizer() {

        // the "_" is important
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyCustomView.handleTapGesture(_:)))
        tapGestureRecognizer.numberOfTapsRequired = 1
        addGestureRecognizer(tapGestureRecognizer)
    }

    // since Swift 3.0 this "_" in the method implementation is very important to 
    // let the selector understand the targetAction
    func handleTapGesture(_ tapGesture : UITapGestureRecognizer) {

        if tapGesture.state == .ended {
            print("TapGesture detected")
        }
    }
}
5
LukeSideWalker

Bei Verwendung von performSelector()

/addtarget()/NStimer.scheduledTimerWithInterval() Methoden Ihre Methode (passend zum Selektor) sollte markiert sein als

@objc
For Swift 2.0:
    {  
        //...
        self.performSelector(“performMethod”, withObject: nil , afterDelay: 0.5)
        //...


    //...
    btnHome.addTarget(self, action: “buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
    //...

    //...
     NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector : “timerMethod”, userInfo: nil, repeats: false)
    //...

}

@objc private func performMethod() {
…
}
@objc private func buttonPressed(sender:UIButton){
….
}
@objc private func timerMethod () {
….
}

Für Swift 2.2 müssen Sie '#selector ()' anstelle von string und selector name schreiben, damit die Möglichkeit von Rechtschreibfehlern und Abstürzen nicht mehr besteht. Unten ist ein Beispiel

self.performSelector(#selector(MyClass.performMethod), withObject: nil , afterDelay: 0.5)
4
sschunara

Wenn Sie # Selektor verwenden, wird Ihr Code beim Kompilieren überprüft, um sicherzustellen, dass die aufzurufende Methode tatsächlich vorhanden ist. Noch besser ist, wenn die Methode nicht vorhanden ist, wird ein Kompilierungsfehler angezeigt: Xcode verweigert die Erstellung Ihrer App und verhindert so, dass eine weitere mögliche Fehlerquelle übersehen wird.

override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.rightBarButtonItem =
            UIBarButtonItem(barButtonSystemItem: .Add, target: self,
                            action: #selector(addNewFireflyRefernce))
    }

    func addNewFireflyReference() {
        gratuitousReferences.append("Curse your sudden but inevitable betrayal!")
    }
3
Swift Developer

Ich fand viele dieser Antworten hilfreich, aber es war nicht klar, wie dies mit etwas geschehen sollte, das kein Knopf war. Ich habe einem UILabel in Swift einen Gestenerkenner hinzugefügt und Probleme gehabt. Nach dem Lesen der obigen Informationen stellte ich fest, dass Folgendes für mich funktioniert hat:

let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: "labelTapped:")

Wo der "Selector" deklariert wurde als:

func labelTapped(sender: UILabel) { }

Beachten Sie, dass es öffentlich ist und dass ich nicht die Selector () - Syntax verwende, aber es ist auch möglich, dies zu tun.

let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: Selector("labelTapped:"))
3
cynistersix

sie erstellen den Selektor wie unten.
1.

UIBarButtonItem(
    title: "Some Title",
    style: UIBarButtonItemStyle.Done,
    target: self,
    action: "flatButtonPressed"
)

2.

flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)

Beachten Sie, dass die @ Selector-Syntax weg ist und durch einen einfachen String ersetzt wird, der die aufzurufende Methode benennt. Es gibt einen Bereich, in dem wir uns alle darüber einig sein können, dass die Ausführlichkeit im Weg steht. Wenn wir deklariert haben, dass es eine Zielmethode namens flatButtonPressed gibt, schreiben wir natürlich besser eine:

func flatButtonPressed(sender: AnyObject) {
  NSLog("flatButtonPressed")
}

den Timer einstellen:

    var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, 
                    target: self, 
                    selector: Selector("flatButtonPressed"), 
                    userInfo: userInfo, 
                    repeats: true)
    let mainLoop = NSRunLoop.mainRunLoop()  //1
    mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode) //2 this two line is optinal

Um vollständig zu sein, hier ist der flatButtonPressed

func flatButtonPressed(timer: NSTimer) {
}
3
Daxesh Nagar

Es kann nützlich sein, zu notieren, wo Sie das Steuerelement einrichten, das die Aktion auslöst.

Ich habe zum Beispiel festgestellt, dass ich beim Einrichten eines UIBarButtonItems die Schaltfläche in viewDidLoad erstellen musste, da ich sonst eine nicht erkannte Selektorausnahme erhalten würde.

override func viewDidLoad() {
    super.viewDidLoad() 

    // add button
    let addButton = UIBarButtonItem(image: UIImage(named: "746-plus-circle.png"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("addAction:"))
    self.navigationItem.rightBarButtonItem = addButton
}

func addAction(send: AnyObject?) {     
    NSLog("addAction")
}
2

Ändern Sie als einfache Zeichenfolgenbezeichnung in der Methode, die Selektorsyntax aufruft

var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)

Danach geben Sie func test () ein.

1
Thar Htet

Auswahl in Swift 4:

button.addTarget(self, action: #selector(buttonTapped(sender:)), for: UIControlEvents.touchUpInside)
0

Für Swift

// Beispielcode zum Erstellen eines Timers

Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)

WHERE
timeInterval:- Interval in which timer should fire like 1s, 10s, 100s etc. [Its value is in secs]
target:- function which pointed to class. So here I am pointing to current class.
selector:- function that will execute when timer fires.

func updateTimer(){
    //Implemetation 
} 

repeats:- true/false specifies that timer should call again n again.
0
CrazyPro007

Für Swift

let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.test), userInfo: nil, repeats: true)

Funktionsdeklaration In derselben Klasse:

@objc func test()
{
    // my function
} 
0
Mustajab Haider