在objective-C中,我们可以(通过导入语言的运行时头文件)执行以下操作:
//Pass a service (usually an object) and ANY protocol
- (void)registerService:(id)service forProtocol:(Protocol *)protocol
{
//Grab the protocol's name (that's why we import runtime.h, it contains the protocol_getname mehod)
NSString *protocolName = [NSString stringWithUTF8String:protocol_getName(protocol)];
//If the object we passed does not conform to the protocol, inform and break
if (![service conformsToProtocol:protocol])
{
NSLog(@"Service: %@ does not conform to protocol: %@", service, protocolName);
return;
}
//Else add service in a collection (array, dictionary) for later use
self.services[protocolName] = service;
}
我在obj-C中使用它作为“穷人的IOC容器”,这是一个用于注入依赖关系的简单注册表。
//The interested party uses this method to obtain the dependency it needs by asking for the object that is registered as responsible for conforming to the Protocol parameter
- (id)serviceForProtocol:(Protocol *)protocol
{
id result;
NSString *protocolName = [NSString stringWithUTF8String:protocol_getName(protocol)];
//Look for the service that conforms to the protocol in the registry dictionary,
result = self.services[protocolName];
//if there is no object meeting the criteria, inform/alert
if (result == nil)
{
NSLog(@"No class registered for protocol: %@", protocolName);
}
//and return the result
return result;
}
试图在Swift中复制这种行为,我发现我们无法像在obj-C中那样访问语言等效的“运行时”API,并且可以理解,因为swift是一项正在进行的工作并且给人们这种访问无疑是有风险的。
但这也意味着我们不能以相同的方式使用协议,即在任何协议的意义上。
我想到的第一个可能的解决方法是混合泛型,任何和其中,但这对于某些事情来说太过分了过去很简单。
所以,我的问题是:在Swift中传递协议(如 ANY协议)的一些提议解决方案是什么?
编辑:我使用Swift中引入的元类型类型取得了一些成功,这在语言设计方面是有意义的,但也没有提供提供“字符串”表示形式的能力。元数据类型可以用作字典中的键。
这当然是随着语言的成熟而添加的功能。
答案 0 :(得分:1)
你有什么尝试?
这样的事情不起作用:
import Foundation
func registerService(service: NSObjectProtocol, forProtocol prot: Protocol) {
let protocolName = NSStringFromProtocol(prot)
if (!service.conformsToProtocol(prot)) {
println("Service: \(service) does not conform to protocol: \(protocolName)")
return
}
//...
}
答案 1 :(得分:0)
我尝试了很长时间,有许多不同的方法(指针,Protocol
),而没有@objc
的唯一解决方案和我发现的纯Swift是关闭的。然后,您需要使用闭包来使用协议并返回值
protocol Proto { }
protocol Proto2 { }
class Foo: Proto { }
class Bar: Proto, Proto2 { }
class Baz: Proto2 { }
class Qux { }
func printConforms(classList: [AnyClass], protoCond: (AnyClass) -> Any?) {
for i in classList {
print(i, terminator: " -> ")
if protoCond(i) != nil {
print("is subscriber")
} else {
print("NOT IS subscriber")
}
}
}
let myClasses: [AnyClass] = [Foo.self, Bar.self, Baz.self, Qux.self]
printConforms(classList: myClasses, protoCond: { $0 as? Proto.Type })
更完整的示例:https://gist.github.com/brunomacabeusbr/eea343bb9119b96eed3393e41dcda0c9
修改强>
另一个更好的解决方案是使用泛型,例如:
protocol Proto { }
class Foo: Proto { }
class Bar: Proto { }
class Baz { }
func filter<T>(classes: [AnyClass], byConformanceTo: T.Type) -> [AnyClass] {
return classes.filter { $0 is T }
}
filter(classes: [Foo.self, Bar.self, Baz.self], byConformanceTo: Proto.Type.self)
// return [Foo.self, Bar.self]