检查类是否符合协议

时间:2015-11-11 22:22:33

标签: swift

我正试图在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,值是类,使用入站协议下载字典并实例化类。超级简单。很快就感觉不可能!

3 个答案:

答案 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。它是模块路由器,也是依赖注入框架。它使用协议来发现模块并注入依赖项。如果你想做一些类似于某些协议的模块,你可以试试。