Каков быстрый эквивалент ответаToSelector?

Я искал googled, но не смог узнать, какой быстрый эквивалент отвечаетToSelector: есть.

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

Ответ 1

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

В случае, когда вам все еще нужен 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::") не совпадает с Selector("sleep:minutes:").

Ответ 2

Нет реальной замены Swift.

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

someObject.someMethod?()

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

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

Даже в 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()
}

Ответ 3

Обновление 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()
}

Ответ 4

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

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

Когда метод объявляется как возвращающий Void, просто используйте:

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

См:

"Методы вызова через факультативную цепочку"
Выдержка из: Apple Inc. "Быстрый язык программирования".
интерактивные книги. https://itun.es/us/jEUH0.l

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

В 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
    }
}

Ответ 8

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

  • Используя responsesToSelector, ответил @Erik_at_Digit
  • Используя '?', ответил @Sulthan

  • И используя оператор as?:

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

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

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

Ответ 9

Для быстрого 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)")
    }
}

Ответ 10

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

@objc protocol ContactDetailsDelegate: class {

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

...

weak var delegate:ContactDetailsDelegate!

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

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

Для swift3

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

self.delegate?.method?()

Ответ 14

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
     }

   }

}

Ответ 15

Эквивалент есть? Оператор:

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

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