Что такое Свифт эквивалент respondsToSelector?
я погуглил, но не смог узнать, что такое swift эквивалент respondsToSelector: есть.
это единственное, что я мог найти (Swift alternative to responstoselector:) но не слишком актуально в моем случае, поскольку его проверка существования делегата, у меня нет делегата, я просто хочу проверить, существует ли новый 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::")и не то же самое, чтоSelector("sleep:minutes:").
нет никакой реальной быстрой замены.
вы можете проверить следующим образом:
someObject.someMethod?()это вызывает метод
someMethodтолько если он определен на объектsomeObjectно вы можете использовать его только для@objcпротоколы, которые объявили метод, какoptional.Swift по своей сути является безопасным языком, поэтому каждый раз, когда вы вызываете метод Swift, он должен знать, что метод существует. Проверка времени выполнения невозможна. Вы не можете просто вызвать случайные методы на случайном объекты.
даже в Obj-C вы должны избегать таких вещей, когда это возможно, потому что он не очень хорошо играет с ARC (ARC затем запускает предупреждения для
performSelector:).однако, при проверке доступных API, вы можете использовать
respondsToSelector:, даже если быстро, если вы имеете дело с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 { ... }когда метод объявляется как возвращающий
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 } }
В настоящее время (Swift 2.1) вы можете проверить его с помощью 3 способов:
- используя respondsToSelector ответил @Erik_at_Digit
используя '?- ответил @Sulthan
и с помощью
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)to:
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 существует и реализует его.
Comments