2015-11-11 53 views
7

我正在尝试在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,值是类,用入站协议为字典下标并实例化类。超级简单。迅速感觉不可能!

回答

4

如果你导入obj-c,那么你可以做一些像你以前一样的东西。

否则,这很难,因为协议不以相同的方式存在。考虑一下工厂的注册系统。您的每个类都将通过提供一个函数或闭包来注册自己,这个函数或闭包可以被调用来返回该类的新实例,并且注册是针对字符串或其他类型的标识符的。这是一个协议类型的好处,但在obj-c中,你真的用字符串转换做同样的事情。你可以注册任何Equatable,以保持非常通用的东西。

+8

'if let foo = bar as? MyProtocol {/ * bar符合协议...... foo是MyProtocol类型,并且可以调用方法* /}' – nhgrif

+0

我最终使用enum作为键和闭包作为值来执行基于注册的swift方法。效果很好。 –

7

通过nhgrif给出的注释是斯威夫特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语句被称作可选结合并检查对象可以是输入到给定的类型/类别/协议/ ....

如果是这样,您可以使用可选的(as?)或force unwrapas!)该对象。

0

此功能将完全满足您的要求:

bool _swift_typeIsTargetType(id sourceType, id targetType)

它可以检查一个迅速的类型是目标类型(为相同类型或子类,或者符合目标协议),就像is快速操作员。但它是一个类型,而不是一个实例:

let sourceType: Any.Type = type(of: self) 
let targetType: Any.Type = AnyProtocol.self 
let result = _swift_typeIsTargetType(sourceType, targetType) 

它使用专用的API在libswiftCore.dylib,见迅速源代码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。它是一个模块路由器,也是一个依赖注入框架。它使用协议来发现模块并注入依赖关系。如果你想做'找到符合某种协议的模块',你可以试试它。