2015-09-04 156 views
1

我很难在Swift中使用协议类型进行类型检查。我有几个协议(在OBJ-C框架中定义),我试图检查他们的类型,像这样:Swift协议比较

public func resolve(proto: Protocol!) -> NSObject { 

    // does not match when called with resolve(Foo) 
    if (proto is Foo) 
    { 
    return FooImpl(); 
    } 

    // other type checking here 

} 

我曾尝试:

// Compile error: Expected member name or constructor call after type name 
if (proto === Foo) 

// Compile error: Expected member name or constructor call after type name 
if (proto == Foo) 

// Works, but seems hackish as it reverts to string comparison 
if (NSStringFromProtocol(proto) == NSStringFromProtocol(Foo)) 

可以这样不使用NSStringFromProtocol做些什么呢?

+0

foo是如何定义的?我猜foo是一个类变量,你是否初始化它?或者你有一个init()方法? (不是nscoder之一),并在那里初始化foo? (在init方法中) – Zich

+0

Foo是一个只在objective-c框架中定义的协议。 –

回答

4

Protocol是一个运行时类型,而不是一个对象。您需要在其上使用运行时功能。

public func resolve(proto: Protocol) -> NSObject { 
    if protocol_isEqual(proto, Foo.self) { 
     return FooImpl() 
    } 

    // other type checking here 
} 

这就是说,这几乎从来都不是在Swift中做事的正确方法。如果你真的需要做这样的工作,你应该使用重载:

func resolve(proto: Foo.Type) -> NSObject { 
    return FooImpl() 
} 

func resolve(proto: Any) -> NSObject { 
    return DefaultIfYouNeedOne() 
} 

斯威夫特会挑选最好的过载。如果你没有Any版本,那更好,因为那么Swift不会让你通过意想不到的类型到resolve

但即使这通常表明你正在做的事情,你可能不应该。如果你需要能够构建这个类,通常你应该只需要添加init()到你的协议。或者为您可以构建的东西创建一个Constructible协议(或者Resolvable或您需要的任何东西)。关注协议,而不是特定的类型。当你发现自己在做很多类型检查时,你可能会与Swift战斗。你可能不得不为了连接到ObjC,但不要创造更多。在Swift中几乎没有任何东西会返回NSObject

无关注:不应在新功能中使用Protocol!。您可能从ObjC自动导入的东西中复制了它,这些东西没有被审计过。如果你知道它不能为零,那么使用这个类型。如果可以为零,则使用可选项。很少有理由通过!

+0

感谢意外的反馈,我不知道运行时功能,这个工程,我现在必须去阅读这个话题。完全同意你对类型检查的评论,这个例子有点用来说明问题:) –