我正在寻找一种从协议类型动态获取协议名称的方法,而不必在协议声明中使用@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
答案 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)