¿Cuál es el equivalente Swift de respondsToSelector?


He buscado en Google pero no he podido averiguar cuál es el equivalente swift a respondsToSelector:.

Esto es lo único que pude encontrar (Alternativa Swift a respondsToSelector:) pero no es demasiado relevante en mi caso ya que es comprobar la existencia del delegado, no tengo un delegado Solo quiero comprobar si existe una nueva API o no cuando se ejecuta en el dispositivo y si no volver a una versión anterior de la api.

Author: Honey, 2014-06-11

16 answers

Como se mencionó, en Swift la mayoría de las veces se puede lograr lo que se necesita con el ? operador de desempaquetado opcional. Esto le permite llamar a un método en un objeto si y solo si el objeto existe (no nil) y el método está implementado.

En el caso de que todavía necesite respondsToSelector:, todavía está allí como parte del protocolo NSObject.

Si estás llamando a respondsToSelector: en un tipo Obj-C en Swift, entonces funciona de la misma manera que esperarías. Si lo está usando por su cuenta Clase Swift, tendrá que asegurarse de que su clase se deriva de NSObject.

Aquí hay un ejemplo de una clase Swift que puede comprobar si responde a un selector:

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 importante que no omita los nombres de los parámetros. En este ejemplo, Selector("sleep::")es no lo mismo que Selector("sleep:minutes:").

 149
Author: Erik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-29 01:57:58

No hay un reemplazo real de Swift.

Puede comprobarlo de la siguiente manera:

someObject.someMethod?()

Esto llama al método someMethod solo si está definido en object someObject pero puede usarlo solo para los protocolos @objc que han declarado el método como optional.

Swift es inherentemente un lenguaje seguro por lo que cada vez que llame a un método Swift tiene que saber que el método está allí. No es posible verificar el tiempo de ejecución. No puedes simplemente llamar a métodos aleatorios en objetos aleatorios.

Incluso en Obj-C debe evitar tales cosas cuando sea posible porque no se juega bien con ARC (ARC luego activa advertencias para performSelector:).

Sin embargo, al verificar las API disponibles, aún puede usar respondsToSelector:, incluso si es Swift, si está tratando con NSObject instancias:

@interface TestA : NSObject

- (void)someMethod;

@end

@implementation TestA

//this triggers a warning

@end   


var a = TestA()

if a.respondsToSelector("someMethod") {
   a.someMethod()
}
 58
Author: Sulthan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-26 20:53:10

Actualización Mar 20, 2017 para Swift 3 sintaxis:

Si no le importa si el método opcional existe, simplemente llame a delegate?.optionalMethod?()

De lo contrario, usar guard es probablemente el mejor enfoque:

weak var delegate: SomeDelegateWithOptionals?

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

Respuesta original:

Puede usar el enfoque "if let" para probar un protocolo facultativo como este:

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()
}
 32
Author: hyouuu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-21 00:12:12

Parece que necesita definir su protocolo como un subprotocolo de NSObjectProtocol ... entonces obtendrá el método respondsToSelector

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

Tenga en cuenta que solo especificar @objc no era suficiente. También debe tener cuidado de que el delegado real sea una subclase de NSObject , lo que en Swift podría no serlo.

 11
Author: Matej Ukmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-20 16:43:19

Si el método para el que está probando se define como un método opcional en un protocolo @objc (que suena como su caso), entonces use el patrón de encadenamiento opcional como:

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

Cuando el método es declare como returning Void, simplemente use:

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

Véase:

"Métodos De Llamada Mediante Encadenamiento Opcional"
Extracto De: Apple Inc. "The Swift Programming Language."
iBooks. https://itun.es/us/jEUH0.l

 10
Author: GoZoner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-07 19:44:03

Las funciones son tipos de primera clase en Swift, por lo que puede verificar si una función opcional definida en un protocolo se ha implementado comparándola con nil:

if (someObject.someMethod != nil) {
    someObject.someMethod!(someArgument)
} else {
    // do something else
}
 9
Author: Christopher Pickslay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-21 22:50:01

En Swift 2,Apple introdujo una nueva característica llamada API availability checking, que podría ser un reemplazo para el método respondsToSelector:.La siguiente comparación de fragmentos de código se copia de la sesión WWDC2015 106 Qué hay de nuevo en Swift que pensé que podría ayudarlo,por favor compruébelo si necesita saber más.

El Viejo Enfoque:

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

El Mejor Enfoque:

@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
    if #available(OSX 10.10.3, *) {
        dropButton.springLoaded = true
    }
}
 7
Author: tounaobun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-13 13:41:18

Para swift3

Si solo desea llamar al método, ejecute el código a continuación.

self.delegate?.method?()

 5
Author: Jason Yu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-23 07:36:20

Actualmente (Swift 2.1) se puede comprobar usando 3 maneras:

  1. Usando respondsToSelector respondido por @Erik_at_Digit
  2. Usando '?' contestado por @Sulthan

  3. Y usando el operador as?:

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

Básicamente depende de lo que usted está tratando de lograr:

  • Si, por ejemplo, la lógica de la aplicación necesita realizar alguna acción y el delegado no está configurado o el delegado apuntado no implementó el método onuccess() (método de protocolo) así que la opción 1 y 3 son la mejor opción, aunque usaría la opción 3, que es Rápida.
  • Si no desea hacer nada cuando delegate es nil o el método no está implementado, use la opción 2.
 4
Author: OhadM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:37

Para 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)")
    }
}
 4
Author: Kakashi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-07 16:55:18

Acabo de implementar esto yo mismo en un proyecto, ver el código a continuación. Como menciona @ Christopher Pickslay, es importante recordar que las funciones son ciudadanos de primera clase y, por lo tanto, pueden tratarse como variables opcionales.

@objc protocol ContactDetailsDelegate: class {

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

...

weak var delegate:ContactDetailsDelegate!

if let deleteContact = delegate.deleteContact {
    deleteContact(contact)
}
 2
Author: Bulwinkel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-23 14:43:59

Otra posible sintaxis de swift..

 if let delegate = self.delegate, method = delegate.somemethod{
        method()
    }
 2
Author: Janub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-01 12:50:33

Cuando comencé a actualizar mi antiguo proyecto a Swift 3.2, solo necesitaba cambiar el método de

respondsToSelector(selector)

A:

responds(to: selector)
 1
Author: chAlexey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-08 10:05:28

Utilizo guard let else, por lo que puede hacer algunas cosas predeterminadas si el func delegado no está implementado.

@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
Author: dichen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-25 22:46:21

Swift 3:

Protocolo

@objc protocol SomeDelegate {
    @objc optional func method()
}

Objeto

class SomeObject : NSObject {

weak var delegate:SomeObject?

func delegateMethod() {

     if let delegateMethod = delegate?.method{
         delegateMethod()
     }else {
        //Failed
     }

   }

}
 -1
Author: etzuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-05 09:11:04

El equivalente es el ? operador:

var value: NSNumber? = myQuestionableObject?.importantMethod()

ImportantMethod solo se llamará si myQuestionableObject existe y lo implementa.

 -4
Author: Ben Gottlieb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-11 16:24:13