【问题标题】:Obtaining a string representation of a protocol dynamically动态获取协议的字符串表示
【发布时间】:2014-10-16 01:21:49
【问题描述】:

我正在寻找一种从协议类型中动态获取协议名称的方法,而不必在协议声明中使用@objc 属性。

我知道这行得通:

func keyForProtocol(aProtocol: Protocol) -> String {
    return NSStringFromProtocol(aProtocol)
}

但仅当协议具有@obj 属性时:

@objc protocol Test {}

var key = keyForProtocol(Test.self)  // Key contains "TestApp.Test"

但是,一旦我删除 @objc 属性,编译就会失败并出现以下错误:

'Test.Protocol' is not convertible to 'Protocol'

有什么方法可以实现吗?

注意:我想避免使用@objc 的原因是它不允许使用关联类型(即协议中的泛型)——在这种情况下编译失败并出现以下错误:@ 987654328@

【问题讨论】:

  • 我不相信这是可以做到的,但我很想知道你想用它实现什么——因为不管它是什么,它可能也行不通:) .我怀疑最好只在编译时考虑 Swift 协议才真正“存在”。我很确定编译后的二进制文件中没有任何可用的协议信息(因此没有对非@objc 协议等的一致性检查)。
  • @Sam:我构建了一个简单的依赖注入框架,允许我将协议绑定到类类型。在我尝试在协议中使用泛型之前它工作得很好,因此需要摆脱 @obj 属性。
  • 是的,@objc 协议可以正常工作,但 Swift 协议不同,您不能在运行时对它们做太多事情。我想说你需要想出一个不同的依赖匹配设计。

标签: swift


【解决方案1】:

我最近通过实现keyForProtocol方法找到了一个解决方案,如下:

func keyForProtocol<P>(aProtocol: P.Type) -> String {
    return ("\(aProtocol)")
}

它适用于任何类型,不仅适用于协议,但我可以接受。

操场上的一些例子:

protocol Test {}
keyForProtocol(Test.self) // Prints "__lldb_expr_92.Test"

class MyClass {}
keyForProtocol(MyClass.self) // Prints "__lldb_expr_92.MyClass"

keyForProtocol(Int.self) // Prints "Swift.Int"

keyForProtocol(UIView.self) // Prints "UIView"

【讨论】:

    【解决方案2】:

    正如安东尼奥所说:

    let protocolDescription = "\(aProtocol)"
    

    将返回一个(有时很奇怪的)协议名称。

    我终于完成了将这个字符串转换回协议的任务:

    let protocolReference = NSProtocolFromString(protocolDescription)
    

    如果您需要像本示例(轻量级/自制依赖管理器)一样从通用参数中检索协议类型,则此技术是完美的:

    class DependencyManager<T> {
      private static func inject(_ aProtocol: T.Type) -> T {
        let application = UIApplication.shared.delegate as! LMApplication
        let dependencies = application.applicationDependencies
    
        let protocolReference = NSProtocolFromString("\(aProtocol)")
        let dependency = dependencies!.object(for: protocolReference)
    
        return dependency! as! T
      }
    }
    

    用法:

    let object: Protocol = DependencyManager.inject(Protocol.self)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      相关资源
      最近更新 更多