我正试图在swift中为我们的应用程序创建一个简单的依赖注入系统,现在为期2天。我对任何解决方案都很灵活,但我想要一些东西,所以我可以说"给我一个符合这个协议的例子"只要它符合所述协议,返回的实际类型可以是任何类型。我尝试了很多东西,包括泛型,但设法弄清楚那些不能(?)真的有效,所以现在我已经完成了基本的工作,如下所示:
protocol AProtocol {
}
class AClass: AProtocol {
}
class MyDiThing {
public static func objectConformingTo(aProtocol: Any) -> Any? {
// And here I want to do something like
if AClass is aProtocol {
return AClass()
}
return nil
}
}
// The calling code ..
let aObject = MyDIThing.objectConformingTo(AProtocol)
我知道,这并不美观,但是现在我对性能/坏代码并不那么挑剔,只要它解决了解耦问题(最好能包含在MyDIThing类中)。如果这是不可能的,我可以对其他解决方案开放。我使用了类似于objective-c的解决方案并取得了很好的成功,只需要一个字典,其中键是NSStringFromProtocol,值是类,使用入站协议下载字典并实例化类。超级简单。很快就感觉不可能!
答案 0 :(得分:8)
nhgrif给出的评论是Swift 2的正确答案。 您应该使用可选的绑定:
if let aObjectWithAProtocol = aObject as? AProtocol {
// object conforms to protocol
someObject.someFunction(aObjectWithAProtocol)
} else {
// object does not conform to protocol
}
此if let something = obj as? type
语句称为 可选绑定 ,并检查对象是否可以类型转换为给定类型/ class / protocol / ... 。
如果是这样,您可以使用可选的(as?
)或强制解包(as!
)对象。
答案 1 :(得分:4)
如果您导入obj-c,那么您可以执行以前的操作。
否则,它很难,因为协议不以相同的方式存在。考虑为您的工厂注册基于系统。每个类都会通过提供一个函数或闭包来注册自己,该函数或闭包可以被调用以返回该类的新实例,并且注册是针对字符串或其他类型的标识符。这是一个拥有协议类型的好地方,但是在obj-c中你通过字符串转换实际上做了同样的事情。你可以注册任何Equatable
的东西来保持非常通用。
答案 2 :(得分:0)
此功能完全符合您的要求:
bool _swift_typeIsTargetType(id sourceType, id targetType)
它可以检查swift类型是否是目标类型(是相同类型或子类,还是符合目标协议),类似于swift中的is
运算符。但它是一种类型,而不是一个实例:
let sourceType: Any.Type = type(of: self)
let targetType: Any.Type = AnyProtocol.self
let result = _swift_typeIsTargetType(sourceType, targetType)
它使用libswiftCore.dylib
中的私有API,请参阅swift源代码Casting.cpp:
bool _conformsToProtocols(const OpaqueValue *value, const Metadata *type, const ExistentialTypeMetadata *existentialType, const WitnessTable **conformances)
可选绑定不一样。它还可以检查一致性,但您无法动态提供要检查的类型:
let targetType: Any.Type = AnyProtocol.self
//error: use of undeclared type: 'targetType'
if let _ = aObject as? targetType {
// object conforms to protocol
} else {
// object does not conform to protocol
}
此功能用于ZIKRouter。它是模块路由器,也是依赖注入框架。它使用协议来发现模块并注入依赖项。如果你想做一些类似于某些协议的模块,你可以试试。