为什么Swift中没有通用的基类?

时间:2014-06-10 09:24:04

标签: swift

文档说

  

请注意

     

Swift类不从通用基类继承。给你上课   定义而不指定超类自动成为基类   你可以上课。“

     

摘自:Apple Inc.“The Swift Programming Language.”iBooks。

对我来说没有多大意义。 Objective-C有一个普遍的基类是有原因的,同样的理由应该适用于Swift,是吗? NSObject管理保留/释放语义,isEqual:hashdescription的默认实现。所有这些功能也可以在Swift中使用。

(Objective-C和Swift使用相同的运行时...)

那么,那是什么呢? Swift类没有定义的超类只是NSObject s,它们构成了引擎盖下的正确根类吗?或者是每个新的根类重复的默认对象行为?或者他们创建了另一个Swift-baseclass? retainrelease的实现非常复杂,因为它需要同时考虑多线程和弱引用。

Swift中是否有通用基类(尽管文档中有说明)?这将非常方便,因为在Objective-C中我可以例如编写扩展,让我将方法调用合并到主要的runloop,如[obj.eventually updateCounter],可以读作"下次主runloop控制时调用-updateCounter。如果在此期间我再次调用此方法,则应该只调用一次。使用此扩展,可以将-[UIView setNeedsDisplay]实现为[self.eventually display];如果没有通用基类(或者可能是谁,谁知道?),这在Swift中不再可能。

2 个答案:

答案 0 :(得分:40)

有几种面向对象的语言可以定义新的根类,包括C ++,PHP和Objective-C,它们工作正常,所以这绝对不是特别的事。

  

Objective-C有一个通用基类

的原因

正如Sulthan所说,这不是真的。 Objective-C中有多个根类,您只需不指定超类就可以定义新的根类。正如Sulthan所提到的,Cocoa本身有几个根类,NSObjectNSProxyObject(ObjC 1.0中的Protocol的根类)。

最初的Objective-C语言非常灵活,理论上有人可以创建自己的根类并创建自己的框架,该框架与Foundation完全不同,并使用与retain完全不同的方法,{ {1}},releasealloc等,如果他愿意,甚至可以实现完全不同的内存管理方式。这种灵活性是关于纯粹的Objective-C语言的一个令人惊奇的事情之一 - 它只是提供了一个薄层,所有其他的东西,如对象的创建和销毁,内存管理等等,都可以由用户决定框架坐在上面。

但是,使用Apple的Objective-C 2.0和现代运行时,需要more work来创建自己的根类。通过添加ARC,为了在ARC中使用对象,您必须实现Cocoa的内存管理方法,如deallocretain。此外,要在Cocoa集合中使用您的对象,您的类还必须实现releaseisEqual:之类的内容。

因此,在现代Cocoa / Cocoa Touch开发中,对象通常必须至少实现一组基本方法,这些方法是hash协议中的方法。 Cocoa中的所有根类(NSObjectNSObject)都实现了NSProxy协议。

  

那么,那是什么呢?是没有定义的Swift类   超类只是NSObjects,它们构成了正确的根类   油烟机?或者是每个新的重复的默认对象行为   根类?或者他们创建了另一个Swift-baseclass?

这是一个很好的问题,你可以通过内省的Objective-C运行时找到答案。在某种意义上,Swift中的所有对象也是Objective-C对象,因为它们可以像Objective-C中的对象一样与Objective-C运行时一起使用。该类的一些成员(未标记为NSObject@objc)可能对Objective-C不可见,但是否则Objective-C运行时的所有内省功能都完全适用于纯Swift的对象类。在Swift中定义的类看起来像Objective-C运行时的任何其他类,除了名称被修改。

使用Objective-C运行时,您可以发现,对于Swift中作为根类的类,从Objective-C的角度来看,它实际上有一个名为dynamic的超类。此SwiftObject类实现了SwiftObject协议的方法,如NSObjectretainreleaseisEqual:等等。实际上并不符合respondsToSelector:协议。这就是如何在没有问题的情况下将纯Swift对象与Cocoa API一起使用。

然而,从Swift内部来看,编译器并不认为Swift根类实现了这些方法。因此,如果您定义根类NSObject,那么如果您尝试调用Foo,它将不会编译它抱怨此方法不存在。但是我们仍然可以用一个技巧 - 回想一下,编译器会让我们在Foo().isKindOfClass(Foo.self)类型的变量上调用任何Objective-C方法(编译器已经听说过),并且方法查找会产生一个隐式的-unwrapped可选功能,在运行时成功或失败。所以我们可以做的是转换为AnyObject,确保导入AnyObjectFoundation(因此声明对编译器是可见的),然后我们可以调用它,它会工作在运行时:

ObjectiveC

基本上,从Objective-C的角度来看,Swift类要么将现有的Objective-C类作为根类(如果它继承自Objective-C类),要么以(Foo() as AnyObject).isKindOfClass(Foo.self) 为根类。

答案 1 :(得分:26)

这主要是设计决策,有些语言具有根类(例如Java)和不具备语言的语言(例如C ++)。

请注意,在Obj-C中,不强制执行根类。您可以轻松创建一个不从任何类继承的对象。您还可以创建自己的根类,Apple API中至少有3个(NSObjectNSProxy和已弃用Object)。

拥有根类的原因主要是历史 - 根类确保所有对象都有一些共同的接口,一些常用的方法(例如isEqualTo:hash()等)是收集所必需的上课。

一旦你有了泛型(或C ++中的模板),拥有根类就不那么重要了。

自{ARC}以来,retain中的releaseNSObject不再重要了。使用MRC,您仍然需要打电话给他们。使用ARC,您永远不会明确地调用这些方法,并且可以在幕后更有效地实现它们。

在Swift中,NSObject中的方法已分为协议 - EquatableHashablePrintableDebugPrintable。这样做的好处是对象可以与结构共享接口。

然而,没有什么可以阻止你继承NSObject的每个班级。该类仍然存在,如果您正在处理Obj-C API,它尤其有用。在纯Swift中,根类不是必需的。

还有一点需要注意:

Swift课程并不在Obj-C之上运行;他们没有在幕后翻译成Obj-C。它们只是由相同的编译器编译,允许它们相互操作。理解这一点非常重要。这就是为什么有时必须添加@objc以提供与Obj-C协议/类的一致性的原因。