什么是Swift相当于respondsToSelector?

我在谷歌上搜索过,但没有找到与respondsToSelector:等价的swift是什么。

这是我唯一能找到的东西(快速替代respondsToSelector:),但在我的情况下并不太相关,因为它检查委托的存在,我没有委托,我只是想检查在设备上运行时是否存在新的API,如果没有回落到API的前一个版本。

110740 次浏览

没有真正的Swift替代品。

您可以通过以下方式进行检查:

someObject.someMethod?()

只有在对象someObject上定义方法时,才会调用someMethod方法,但只能用于声明方法为optional@objc协议。

Swift本质上是一种安全的语言,所以每次你调用一个方法时,Swift都必须知道这个方法在那里。不可能进行运行时检查。你不能对随机对象调用随机方法。

即使在Obj-C中,你也应该尽可能避免这样的事情,因为它不能很好地使用ARC(然后ARC会触发performSelector:的警告)。

然而,当检查可用的api时,你仍然可以使用respondsToSelector:,即使是Swift,如果你正在处理NSObject实例:

@interface TestA : NSObject


- (void)someMethod;


@end


@implementation TestA


//this triggers a warning


@end

< br >

var a = TestA()


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

等价的是?接线员:

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

importantMethod只在myQuestionableObject存在并实现它时才会被调用。

如前所述,在Swift 大多数时候,你可以通过?可选的解包装操作符来实现你所需要的中。这允许你当且仅当对象存在(不是nil)并且方法已经实现时调用该对象的方法。

在你仍然需要respondsToSelector:的情况下,它仍然是NSObject协议的一部分。

如果你在Swift中的Obj-C类型上调用respondsToSelector:,那么它的工作原理与你预期的一样。如果你在你自己的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:")相同。

如果你要测试的方法被定义为@objc协议中的可选方法(听起来像你的情况),那么使用可选的链接模式如下:

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

当方法声明为返回Void时,只需使用:

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

看到的:

" Calling Methods Through Optional chainaining "
. 摘自:苹果公司《快速编程语言》
iBooks。https://itun.es/us/jEUH0.l < / p >

看起来你需要把你的协议定义为NSObjectProtocol的子协议…然后你会得到respondsToSelector方法

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

注意,只指定@objc是不够的。你还应该注意,实际的委托是NSObject的子类——在Swift中可能不是。

2017年3月20日更新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()
}

函数在Swift中是一类类型,所以你可以通过将协议中定义的可选函数与nil进行比较来检查它是否已经实现:

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

我只是在一个项目中实现了这一点,见下面的代码。正如@Christopher Pickslay提到的,重要的是要记住函数是第一类公民,因此可以像可选变量一样对待。

@objc protocol ContactDetailsDelegate: class {


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


...


weak var delegate:ContactDetailsDelegate!


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

在Swift 2中,苹果引入了一个名为API availability checking的新功能,它可能是respondsToSelector:方法的替代品。下面的代码片段比较来自WWDC2015会议106 斯威夫特有什么新动向,我认为这可能对你有帮助,如果你需要了解更多,请查看它。

老方法:

@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..另一种可能的语法。

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

目前(Swift 2.1)你可以用3种方式检查它:

  1. 使用@Erik_at_Digit回答的respondstoselectorismemberofclass
  2. 使用'?'由@Sulthan回答

  3. 并且使用as?操作符:

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

Basically it depends on what you are trying to achieve:

  • If for example your app logic need to perform some action and the delegate isn't set or the pointed delegate didn't implement the onSuccess() method (protocol method) so option 1 and 3 are the best choice, though I'd use option 3 which is Swift way.
  • If you don't want to do anything when delegate is nil or method isn't implemented then use option 2.

我使用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.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)")
}
}

斯威夫特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
}


}


}

对于swift3

如果您只想调用该方法,请运行下面的代码。

self.delegate?.method?()

当我开始将我的旧项目更新到Swift 3.2时,我只需要更改方法

respondsToSelector(selector)

:

responds(to: selector)

我猜你想为委托做一个默认实现。你可以这样做:

let defaultHandler = {}
(delegate?.method ?? defaultHandler)()