Что такое Свифт эквивалент respondsToSelector?

я погуглил, но не смог узнать, что такое swift, эквивалентный respondsToSelector: есть.

это единственное, что я смог найти (Свифт альтернатива respondsToSelector:), но не слишком актуально в моем случае, поскольку его проверка существования делегата, у меня нет делегата, я просто хочу проверить, существует ли новый API или нет при запуске на устройстве, а если нет, то вернуться к предыдущей версии api.

16 ответов


как уже упоминалось, в Swift большую часть времени вы можете добиться того, что вам нужно, с ? необязательный оператор unwrapper. Это позволяет вызывать метод для объекта, если и только если объект существует (не ) и метод.

в случае, когда вам все еще нужно respondsToSelector:, он все еще там как часть NSObject протокол.

если вы звоните respondsToSelector: на типе Obj-C в Swift, тогда он работает так же, как и вы ожидать. Если вы используете его в своем собственном классе Swift, вам нужно будет убедиться, что ваш класс является производным от NSObject.

вот пример класса Swift, который вы можете проверить, отвечает ли он селектору:

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

важно, чтобы вы не опускали имена параметров. В этом примере Selector("sleep::") is не аналогично Selector("sleep:minutes:").


нет реальной быстрой замены.

вы можете проверить следующим образом:

someObject.someMethod?()

это вызывает метод someMethod только если он определен на объект someObject но вы можете использовать его только для @objc протоколы, которые объявили метод, как optional.

Swift по своей сути является безопасным языком, поэтому каждый раз, когда вы вызываете метод Swift, он должен знать, что метод есть. Проверка времени выполнения невозможна. Вы не можете просто вызвать случайные методы на random объекты.

даже в Obj-C вы должны избегать таких вещей, когда это возможно, потому что он не играет хорошо с ARC (ARC затем запускает предупреждения для performSelector:).

однако, при проверке доступных API, вы можете использовать respondsToSelector:, даже если Swift, если вы имеете дело с NSObject случаях:

@interface TestA : NSObject

- (void)someMethod;

@end

@implementation TestA

//this triggers a warning

@end   


var a = TestA()

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

обновление 20 марта 2017 для синтаксиса Swift 3:

Если вам все равно, существует ли дополнительный метод, просто вызовите delegate?.optionalMethod?()

в противном случае, используя guard, вероятно, лучший подход:

weak var delegate: SomeDelegateWithOptionals?

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

оригинальный ответ:

вы можете использовать подход "if let" для тестирования дополнительного протокола следующим образом:

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()
}

Кажется, вам нужно определить свой протокол как подпротокол NSObjectProtocol ... тогда вы получите способ respondsToSelector

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

обратите внимание, что недостаточно указать только @objc. Вы также должны быть осторожны, что фактический делегат является подклассом NSObject - который в Swift может не быть.


Если метод тестируется определяется как дополнительный метод на @objc протокол (который звучит как ваш случай), затем используйте дополнительные цепочки узор в виде:

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

когда метод объявляется как returning Void, просто использовать:

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

посмотреть:

"Вызов Методов Через Необязательную Цепочку"
Выдержка Из: Apple Inc. "Язык Программирования Swift."
в iBooks. https://itun.es/us/jEUH0.l


функции являются первоклассными типами в Swift, поэтому вы можете проверить, была ли реализована дополнительная функция, определенная в протоколе, сравнивая ее с nil:

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

в Swift 2,Apple представила новую функцию под названием API availability checking, который может быть заменой для respondsToSelector: метод.Следующее сравнение фрагментов кода копируется из сеанса WWDC2015 106 Что нового в Swift мне кажется, может помочь вам,пожалуйста, проверьте его, если вам нужно знать больше.

Старый Подход:

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

Лучший Подход:

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

для swift3

Если вы просто хотите вызвать метод, выполните ниже код.

self.delegate?.method?()


В настоящее время (Swift 2.1) вы можете проверить его, используя 3 способа:

  1. используя respondsToSelector ответил @Erik_at_Digit
  2. используя '?' ответил @Sulthan

  3. и с помощью as? оператор:

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

в основном это зависит от того, что вы пытаетесь достичь:

  • если, например, ваша логика приложения должна выполнить некоторые действия и делегат не установлен или указанный делегат не реализовал метод onSuccess () (метод протокола), поэтому вариант 1 и 3-лучший выбор, хотя я бы использовал вариант 3, который является быстрым способом.
  • если вы не хотите ничего делать, когда делегат равен нулю или метод не реализован, используйте опцию 2.

для 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)")
    }
}

Я просто реализую это сам в проекте, см. код ниже. Как упоминает @Christopher Pickslay, важно помнить, что функции являются гражданами первого класса и поэтому могут рассматриваться как необязательные переменные.

@objc protocol ContactDetailsDelegate: class {

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

...

weak var delegate:ContactDetailsDelegate!

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

другой возможный синтаксис swift..

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

когда я начал обновлять свой старый проект до Swift 3.2, мне просто нужно было изменить метод с

respondsToSelector(selector)

в:

responds(to: selector)

Я использую guard let else, Так что могу сделать некоторые вещи по умолчанию, если делегат func не реализован.

@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)")
    }
}

Swift 3:

протокол

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

объект

class SomeObject : NSObject {

weak var delegate:SomeObject?

func delegateMethod() {

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

   }

}

эквивалент ? оператор:

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

importantMethod будет вызываться, только если myQuestionableObject существует и реализует его.