[英]Passing Protocol Type as parameter in Swift
在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是一項正在進行的工作並且給予了人們這種訪問無疑具有風險。
但這也意味着我們不能再以相同的方式使用協議,即在任何協議的意義上。
我想到的第一個可能的解決方法是混合使用泛型 , Any和where ,但對於過去簡單的東西來說,感覺太多了。
所以,我的問題是:在Swift中傳遞協議 (如在任何協議中 )的一些提議解決方案是什么?
編輯:我使用Swift中引入的元類型類型取得了一些成功,這在語言設計方面是有意義的,但也沒有提供能夠提供元數據類型的“字符串”表示的能力,該元數據類型可用作字典。
這當然是隨着語言的成熟而添加的功能。
你有什么嘗試?
這樣的事情不起作用:
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
}
//...
}
我嘗試了很長時間,有許多不同的方法(指針, 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]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.