什么是Swift等效的respondsToSelector?

时间:2014-06-11 16:16:14

标签: objective-c swift selector

我用Google搜索但未能找到与respondsToSelector:相当的快捷方式。

这是我能找到的唯一的东西(Swift alternative to respondsToSelector:),但在我的情况下,由于检查代表的存在,我没有太多相关性,我没有代表我只是想要在设备上运行时检查是否存在新API,如果没有,则回退到先前版本的api。

17 个答案:

答案 0 :(得分:159)

如上所述,在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:")相同。

答案 1 :(得分:59)

没有真正的Swift替代品。

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

someObject.someMethod?()

仅当方法someMethod在对象someObject上定义时调用方法@objc,但您只能将其用于已声明方法为optional的{​​{1}}协议。

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

答案 2 :(得分:34)

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

原始回答:

你可以使用"如果让"测试这样的可选协议的方法:

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

答案 3 :(得分:11)

您似乎需要将协议定义为NSObjectProtocol的子协议...然后您将获得respondsToSelector方法

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

请注意,仅指定@objc是不够的。你应该小心实际的委托是NSObject的子类 - 在Swift中可能不是。

答案 4 :(得分:10)

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

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

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

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

请参阅:

  

“通过可选链接调用方法”
  摘录自:Apple Inc.“The Swift Programming Language。”
  iBooks的。 https://itun.es/us/jEUH0.l

答案 5 :(得分:9)

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

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

答案 6 :(得分:7)

在Swift 2中,Apple引入了一项名为API availability checking的新功能,该功能可能是respondsToSelector:方法的替代品。以下代码段比较是从WWDC2015会话106 What's New in 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
    }
}

答案 7 :(得分:6)

对于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)")
    }
}

答案 8 :(得分:5)

对于swift3

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

self.delegate?.method?()

答案 9 :(得分:4)

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

  1. 使用@Erik_at_Digit回答的respondsToSelector
  2. 使用@ {Sulthan

  3. 回答的'?'
  4. 并使用as?运算符:

    if let delegateMe = self.delegate as? YourCustomViewController
    {
       delegateMe.onSuccess()
    }
    
  5. 基本上取决于你想要达到的目标:

    • 例如,如果您的应用程序逻辑需要执行某些操作并且未设置委托或指向的委托未实现onSuccess()方法(协议方法),那么选项1和3是最佳选择,尽管我使用选项3,这是Swift方式。
    • 如果您在委托为零或未实施方法时不想做任何事情,请使用选项2.

答案 10 :(得分:2)

我在项目中自己实现,请参阅下面的代码。正如@Christopher Pickslay所提到的,重要的是要记住,函数是一等公民,因此可以被视为可选变量。

@objc protocol ContactDetailsDelegate: class {

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

...

weak var delegate:ContactDetailsDelegate!

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

答案 11 :(得分:2)

swift的另一种可能的语法..

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

答案 12 :(得分:1)

当我开始将旧项目更新为Swift 3.2时,我只需要从

更改方法
respondsToSelector(selector)

为:

responds(to: selector)

答案 13 :(得分:0)

我猜您想为委托创建默认实现。您可以这样做:

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

答案 14 :(得分:0)

我使用SELECT ... INTO OUTFILE,因此如果未实现委托功能,可以执行一些默认操作。

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "sync"
)

func main() {

    rawJson := []byte(`{
            "Foo": {
                "Bar": "Baz"
            }
        }`)

    bzip2Reader := bytes.NewReader(rawJson) // this stands in for the bzip2.NewReader

    var wg sync.WaitGroup
    wg.Add(2)

    r, w := io.Pipe()

    go func() {
        // write everything into the pipe. Decompression happens in this goroutine.
        io.Copy(w, bzip2Reader)
        w.Close()
        wg.Done()
    }()

    decoder := json.NewDecoder(r)

    go func() {
        for {
            t, err := decoder.Token()
            if err != nil {
                break
            }
            fmt.Println(t)
        }
        wg.Done()
    }()

    wg.Wait()
}

答案 15 :(得分:-1)

斯威夫特3:

协议

class SomeObject : NSObject {

weak var delegate:SomeObject?

func delegateMethod() {

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

   }

}

对象

{{1}}

答案 16 :(得分:-4)

相当于?操作者:

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

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