什么是 NSObject<Protocol> 的 swift 等价物?

Posted

技术标签:

【中文标题】什么是 NSObject<Protocol> 的 swift 等价物?【英文标题】:whats the swift equivalent of NSObject<Protocol>? 【发布时间】:2015-08-11 17:51:00 【问题描述】:

我有一个类需要使用 NSObject 子类的变量进行设置,并且实现了某个协议。

protocol ProtoTest 
    var foo: Int  get set 



class AClass: NSObject,  ProtoTest 
    var foo: Int = 3



class BClass: NSObject,  ProtoTest 
    var foo: Int = 4


class Consumer 

    var protoInstance: ProtoTest?  //Does not cary any information of the class just the protocol
    var protoInstance2: protocol<NSObjectProtocol, ProtoTest>?

    init(x: ProtoTest) 
        self.protoInstance = x
        self.protoInstance2 = nil
    

    init(x: protocol<NSObjectProtocol, ProtoTest>) 
        self.protoInstance2 = x
        self.protoInstance = nil
    

    func doSomething() 
        if let x = protoInstance 
            x.copy() //'ProtoTest' does not have a member named 'copy'
        
        if let x = protoInstance2 
            x.copy()    //protocol<NSObjectProtocol, ProtoTest> does not have a member named 'copy'

        
    

在上面的例子中,变量的声明都不起作用。因为他们都不知道基类?

如何快速实现这一点?

【问题讨论】:

【参考方案1】:

通常相当于 Swift 中的NSObject&lt;Protocol&gt; 就是Protocol。通常,这个协议被声明为一个类协议,以保证它会被一个类所采用。

如果你还需要NSObject协议方法(比如respondsToSelector:,那么让Protocol采用NSObjectProtocol。

如果问题仅仅是你想调用copy()而你无法说服编译器让你这样做,那么也采用NSCopying(或者只是使用respondsToSelector:performSelector:绕过编译器完全)。

【讨论】:

【参考方案2】:

您可以通过多种方式做到这一点。首先,您可以将Consumer 设为通用:

class Consumer<T: NSObject where T: Prototest> 
    var protoInstance: T?
    var protoInstance2: T?

如果您这样做,那么所有对protoInstanceprotoInstance2 的引用都将继承自NSObject,并且您将能够直接在对象上调用.copy() 之类的方法。

如果您不希望 Consumer 是泛型的,您可以使用泛型参数强制限制 init 方法,如下所示:

class Consumer 
    // ...
    init<T: NSObject where T: Prototest>(x: T) 
        protoInstance = x
    

如果您这样做,您将保证 protoInstance 将是 NSObject,但您必须强制转换为 NSObject 才能使用 NSObject 的任何方法:

func doSomething() 
    if let x = protoInstance as? NSObject 
        x.copy()
    

编辑:

请注意,我不确定您是否真的希望 protoInstanceprotoInstance2 属于不同类型,您的问题我有点不清楚。如果您确实希望它们是不同的类型,我可以在此答案中添加其他建议。

【讨论】:

谢谢 Roman,所以你认为没有办法在变量声明中强制执行 NSObject 吗? 您可以将变量定义为var protoInstance: NSObject?,然后在您想使用它时转换为Prototest。但是如果你想强制该属性既是NSObject Prototest,那么你将不得不在某处使用泛型...... @EdwardAshak “所以你认为没有办法强制执行 NSObject” 为什么你认为你需要这样做? 对所有init 方法施加通用约束可确保变量仅使用NSObject 类型进行初始化。因此,即使变量不限于NSObject,实际上您也可以始终转换为NSObject,并确保转换成功。 这个变量被初始化为AClass类型的对象,它是NSObject的子类并实现了协议。我允许将变量设置为与定义中的 AClass 等效的任何对象,该对象在某些时候也被视为 NSObject。我希望这能澄清一点

以上是关于什么是 NSObject<Protocol> 的 swift 等价物?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 协议 protocol

Protocol其他用法

Protocol类型限制

协议(Protocol)与委托代理(Delegate)

Objective C Protocol implementation

oc63--协议@protocol1