代码之家  ›  专栏  ›  技术社区  ›  Mark A. Donohoe

在Swift中,如何测试一个对象是否实现了一个可选的协议方法,该方法在没有实际调用该方法的情况下因签名不同而不同?

  •  0
  • Mark A. Donohoe  · 技术社区  · 6 年前

    考虑一下这个代码。。。

    @objc public protocol TestDelegate : AnyObject {
        @objc optional func testx()
        @objc optional func test(with string:String)
        @objc optional func test(with2 int:Int)
    }
    
    let delegate:TestDelegate? = nil
    
    if let _ = delegate?.test(with:) {
        print("supports 'test(with:)'")
    }
    
    if let _ = delegate?.testx {
        print("supports 'testx'")
    }
    

    如果你把上面的东西贴在操场上,效果会和预期的一样。

    但是,如果你改变 testx test ,它不再工作。

    同样,如果你改变 test(with2) test(with) 那也不行。

    有没有办法测试那些只在签名上有区别的方法?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Shivam Gaur    6 年前

    嘿MarqueIV检查可选的你可以使用内置函数

    func响应(到Selector:Selector!)-&燃气轮机;布尔

    返回一个布尔值,该值指示接收方是实现还是继承可以响应指定消息的方法。

    应用程序负责确定错误响应是否应被视为错误。

    不能通过使用super关键字向对象发送响应(to:)来测试对象是否从其超类继承方法。

    此方法仍将测试对象作为一个整体,而不仅仅是超类实现。

    相反,您必须直接在objects超类上调用NSObject类方法instancessponse(to:),如下面的代码片段所示。

    清单1

    if( [MySuperclass instancesRespondToSelector:@selector(aMethod)] ) {
        // invoke the inherited method
        [super aMethod];
    }
    

    不能简单地使用[[self superclass]instancesRespondToSelector:@selector(aMethod)],因为如果子类调用该方法,则可能导致该方法失败。

    请注意,如果接收器能够将选择器消息转发给另一个对象,那么它将能够响应消息,尽管是间接的,即使此方法返回false。 参数
    A选择器
    标识消息的选择器。 SDK iOS 2.0+、macOS 10.0+、tvOS 9.0+、watchOS 2.0+

        2
  •  1
  •   Hamish    6 年前

    如中所示 How do I resolve "ambiguous use of" compile error with Swift #selector syntax? ,您可以显式强制函数引用其预期类型,以解决此类歧义。

    唯一的区别是,这样的函数引用 @optional 协议要求通过可选链接完成,需要强制到可选类型的函数。从那里,你可以做一个比较 nil 为了确定两个委托是否都是非nil的,它实现了给定的需求。

    import Foundation
    
    @objc public protocol TestDelegate : AnyObject {
      @objc optional func test()
    
      // Need to ensure the requirements have different selectors.
      @objc(testWithString:) optional func test(with string: String)
      @objc(testWithInt:) optional func test(with int: Int)
    }
    
    class C : TestDelegate {
      func test() {}
      func test(with string: String) {}
      func test(with string: Int) {}
    }
    
    var delegate: TestDelegate? = C()
    
    if delegate?.test as (() -> Void)? != nil {
      print("supports 'test'")
    }
    
    if delegate?.test(with:) as ((String) -> Void)? != nil {
      print("supports 'test w/ String'")
    }
    
    if delegate?.test(with:) as ((Int) -> Void)? != nil {
      print("supports 'test w/ Int'")
    }
    
    // supports 'test'
    // supports 'test w/ String'
    // supports 'test w/ Int'
    

    注意,我已经给出了 test(with:) 要求唯一的选择器,以确保它们不冲突(这不影响消除歧义,只允许类 C TestDelegate ).