动态获取协议的字符串表示形式

时间:2014-08-22 08:32:03

标签: swift

我正在寻找一种从协议类型动态获取协议名称的方法,而不必在协议声明中使用@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的原因是它不允许使用关联类型(即协议中的泛型) - 在这些情况下,编译因此错误而失败:Method cannot be marked @objc because the type of parameter xx cannot be represented in Objective-C

2 个答案:

答案 0 :(得分:2)

我最近通过实施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"

答案 1 :(得分:0)

安东尼奥说:

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)