it-swarm.com.de

Was ist das Swift Äquivalent zu responsondsToSelector?

Ich habe gegoogelt, konnte aber nicht herausfinden, was Swift entspricht respondsToSelector: ist.

Dies ist das einzige, was ich finden konnte ( schnelle Alternative zu responsondsToSelector: ), aber es ist in meinem Fall nicht zu relevant, da es die Existenz des Delegierten überprüft. Ich habe keinen Delegierten, den ich nur möchte um zu überprüfen, ob eine neue API vorhanden ist oder nicht, wenn sie auf dem Gerät ausgeführt wird und wenn nicht auf eine frühere Version der API zurückgegriffen wird.

188
Gruntcakes

Wie bereits erwähnt, können Sie in Swift die meiste Zeit können Sie mit dem optionalen Unwrapper-Operator ? Erreichen, was Sie benötigen eine Methode aufrufen auf ein Objekt, wenn und nur wenn das Objekt existiert (nicht nil) und die Methode implementiert ist.

Für den Fall, dass Sie noch respondsToSelector: Benötigen, ist es im Rahmen des NSObject -Protokolls immer noch vorhanden.

Wenn Sie respondsToSelector: Für einen Obj-C-Typ in Swift aufrufen, funktioniert dies genauso wie erwartet. Wenn Sie es alleine verwenden Swift class, müssen Sie sicherstellen, dass Ihre Klasse von NSObject abgeleitet ist.

Hier ist ein Beispiel einer Swift Klasse, die Sie überprüfen können, ob sie auf einen Selektor reagiert:

class Worker : NSObject
{
    func work() { }
    func eat(food: AnyObject) { }
    func sleep(hours: Int, minutes: Int) { }
}

let worker = Worker()

let canWork = worker.respondsToSelector(Selector("work"))   // true
let canEat = worker.respondsToSelector(Selector("eat:"))    // true
let canSleep = worker.respondsToSelector(Selector("sleep:minutes:"))    // true
let canQuit = worker.respondsToSelector(Selector("quit"))   // false

Es ist wichtig, dass Sie die Parameternamen nicht auslassen. In diesem Beispiel ist Selector("sleep::")nicht dasselbe wie Selector("sleep:minutes:").

161
Erik

Es gibt keinen wirklichen Swift Ersatz.

Sie können auf folgende Weise prüfen:

someObject.someMethod?()

Dadurch wird die Methode someMethod nur aufgerufen, wenn sie für das Objekt someObject definiert ist. Sie kann jedoch nur für @objc - Protokolle verwendet werden, die die Methode als optional deklariert haben.

Swift ist von Natur aus eine sichere Sprache. Jedes Mal, wenn Sie eine Methode aufrufen, muss Swift wissen, dass die Methode vorhanden ist. Es ist keine Laufzeitüberprüfung möglich. Sie können nicht einfach zufällige Methoden für zufällige Objekte aufrufen.

Auch in Obj-C sollten Sie solche Dinge nach Möglichkeit vermeiden, da dies mit ARC nicht gut funktioniert (ARC löst dann Warnungen für performSelector: Aus).

Wenn Sie nach verfügbaren APIs suchen, können Sie dennoch respondsToSelector: Verwenden, auch wenn Sie Swift verwenden, wenn Sie es mit NSObject -Instanzen zu tun haben:

@interface TestA : NSObject

- (void)someMethod;

@end

@implementation TestA

//this triggers a warning

@end   


var a = TestA()

if a.respondsToSelector("someMethod") {
   a.someMethod()
}
59
Sulthan

pdate 20. März 2017 für Swift 3 Syntax:

Wenn es Ihnen egal ist, ob die optionale Methode existiert, rufen Sie einfach delegate?.optionalMethod?() auf.

Andernfalls ist die Verwendung von guard wahrscheinlich der beste Ansatz:

weak var delegate: SomeDelegateWithOptionals?

func someMethod() {
    guard let method = delegate?.optionalMethod else {
        // optional not implemented
        alternativeMethod()
        return
    }
    method()
}

rsprüngliche Antwort:

Mit dem "if let" -Ansatz können Sie ein optionales Protokoll wie das folgende testen:

weak var delegate: SomeDelegateWithOptionals?

func someMethod() {
  if let delegate = delegate {
    if let theMethod = delegate.theOptionalProtocolMethod? {
      theMethod()
      return
    }
  }
  // Reaching here means the delegate doesn't exist or doesn't respond to the optional method
  alternativeMethod()
}
35
hyouuu

Anscheinend müssen Sie Ihr Protokoll als Unterprotokoll von NSObjectProtocol definieren ... dann erhalten Sie die Methode responsondsToSelector

@objc protocol YourDelegate : NSObjectProtocol
{
    func yourDelegateMethod(passObject: SomeObject)
}

beachten Sie, dass es nicht ausreicht, nur @objc anzugeben. Sie sollten auch darauf achten, dass der tatsächliche Delegat eine Unterklasse von NSObject ist - was in Swift möglicherweise nicht der Fall ist.

11
Matej Ukmar

Wenn die Methode, auf die Sie testen, als optionale Methode in einem @ objc -Protokoll definiert ist (was wie in Ihrem Fall klingt), verwenden Sie optionale Verkettung Muster als:

if let result = object.method?(args) {
  /* method exists, result assigned, use result */
}
else { ... }

Wenn die Methode als returning Void deklariert ist, verwenden Sie einfach:

if object.method?(args) { ... }

Sehen:

"Aufruf von Methoden durch optionale Verkettung"
Auszug aus: Apple Inc. "The Swift Programming Language."
iBooks. https://itun.es/us/jEUH0.l

10
GoZoner

Funktionen sind in Swift erstklassige Typen. Sie können also überprüfen, ob eine in einem Protokoll definierte optionale Funktion implementiert wurde, indem Sie sie mit nil vergleichen:

if (someObject.someMethod != nil) {
    someObject.someMethod!(someArgument)
} else {
    // do something else
}

In Swift 2) hat Apple eine neue Funktion namens API availability checking Eingeführt, die möglicherweise die respondsToSelector: - Methode ersetzt. Der folgende Codefragmentvergleich wurde aus dem WWDC2015 kopiert Sitzung 106 Was ist neu in Swift? Ich dachte, das könnte Ihnen helfen. Sehen Sie sich das an, wenn Sie mehr wissen möchten.

Der alte Ansatz:

@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
    if dropButton.respondsToSelector("setSpringLoaded:") {
        dropButton.springLoaded = true
    }
}

Der bessere Ansatz:

@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
    if #available(OSX 10.10.3, *) {
        dropButton.springLoaded = true
    }
}
7
tounaobun

Für Swift 3.0

import UIKit

@objc protocol ADelegate : NSObjectProtocol {

    @objc optional func hi1()
    @objc optional func hi2(message1:String, message2:String)
}

class SomeObject : NSObject {

    weak var delegate:ADelegate?

    func run() {

        // single method
        if let methodHi1 = delegate?.hi1 {
            methodHi1()
        } else {
            print("fail h1")
        }

        // multiple parameters
        if let methodHi2 = delegate?.hi2 {
            methodHi2("superman", "batman")
        } else {
            print("fail h2")
        }
    }
}

class ViewController: UIViewController, ADelegate {

    let someObject = SomeObject()

    override func viewDidLoad() {
        super.viewDidLoad()

        someObject.delegate = self
        someObject.run()
    }

    // MARK: ADelegate
    func hi1() {

        print("Hi")
    }

    func hi2(message1: String, message2: String) {

        print("Hi \(message1) \(message2)")
    }
}
6
Kakashi

Für Swift3

Wenn Sie nur die Methode aufrufen möchten, führen Sie den folgenden Code aus.

self.delegate?.method?()

6
Jason Yu

Derzeit (Swift 2.1) können Sie dies auf drei Arten überprüfen:

  1. Mit responsondsToSelector beantwortet von @Erik_at_Digit
  2. Mit '?' beantwortet von @Sulthan

  3. Und mit as? Operator:

    if let delegateMe = self.delegate as? YourCustomViewController
    {
       delegateMe.onSuccess()
    }
    

Grundsätzlich kommt es darauf an, was Sie erreichen wollen:

  • Wenn zum Beispiel Ihre App-Logik eine Aktion ausführen muss und der Delegat nicht festgelegt ist oder der spitze Delegat die onSuccess () -Methode (Protokollmethode) nicht implementiert hat, sind Option 1 und 3 die beste Wahl, obwohl ich sie verwenden würde Option 3, die Swift Weg ist.
  • Wenn Sie nichts tun möchten, wenn der Delegat null ist oder die Methode nicht implementiert ist, verwenden Sie Option 2.
4
OhadM

eine andere mögliche Syntax von Swift ..

 if let delegate = self.delegate, method = delegate.somemethod{
        method()
    }
2
Janub

Ich implementiere das einfach selbst in ein Projekt, siehe Code unten. Wie @Christopher Pickslay erwähnt, ist es wichtig, sich daran zu erinnern, dass Funktionen erstklassige Bürger sind und daher wie optionale Variablen behandelt werden können.

@objc protocol ContactDetailsDelegate: class {

    optional func deleteContact(contact: Contact) -> NSError?
}

...

weak var delegate:ContactDetailsDelegate!

if let deleteContact = delegate.deleteContact {
    deleteContact(contact)
}
2
Bulwinkel

Als ich anfing, mein altes Projekt auf Swift 3.2) zu aktualisieren, musste ich nur die Methode von ändern

respondsToSelector(selector)

zu:

responds(to: selector)
1
chAlexey

Ich benutze guard let else, so dass einige Standard-Funktionen ausgeführt werden können, wenn die Delegate-Funktion nicht implementiert ist.

@objc protocol ViewController2Delegate: NSObjectProtocol {

    optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnVoid string: String)

    optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnString string: String) -> String
}

class ViewController2: UIViewController {

    weak var delegate: ViewController2Delegate?        

    @IBAction func onVoidButtonClicked(sender: AnyObject){

        if (delegate != nil && delegate!.respondsToSelector(Selector("viewController2:didSomethingWithStringAndReturnVoid:"))) {
            NSLog("ReturnVoid is implemented")

            delegate!.viewController2!(self, didSomethingWithStringAndReturnVoid: "dummy")
        }
        else{
            NSLog("ReturnVoid is not implemented")
            // Do something by default
        }
    }

    @IBAction func onStringButtonClicked(sender: AnyObject){

        guard let result = delegate?.viewController2?(self, didSomethingWithStringAndReturnString: "dummy") else {
            NSLog("ReturnString is not implemented")
            // Do something by default
            return
        }

        NSLog("ReturnString is implemented with result: \(result)")
    }
}
0
dichen