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

文件说

注意

Swift类不会从通用基类inheritance。 您定义的类而不指定超类自动成为基础类,供您进行构build。

摘录自:苹果公司“ Swift编程语言。 “iBooks。

对我来说没有什么意义。 Objective-C有一个普遍基类的原因,Swift也适用于同样的原因吗? NSObjectpipe理保留/释放语义, isEqual:hashdescription的默认实现。 所有这些function都可以在Swift中使用。

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

那么,这是怎么回事? Swift类没有定义的超类NSObject是否构成正确的根类? 或者是为每个新的根类别重复默认的对象行为? 还是他们创造了另一个Swift的基类? retainrelease的实现是非常复杂的,因为它需要同时考虑multithreading和弱引用。

在Swift中可能有一个通用的基类(尽pipe文档说了什么)? 这将是非常方便的,因为在Objective-C中,我可以编写扩展名,使我可以将方法调用合并到主runloop中,例如[obj.eventually updateCounter] ,可以将其读作“call -updateCounter ,下一次主runloop进入如果在此期间再次调用这个方法,那么只能调用一次,这个扩展可以实现-[UIView setNeedsDisplay]作为[self.eventually display];这在Swift中不再可能是不是普遍的基类(或者是,谁知道?)

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

Objective-C具有通用基类是有原因的

正如苏丹所提到的,这不是事实。 Objective-C中有多个根类,您可以通过不指定超类来定义一个新的根类。 正如Sulthan也提到,Cocoa本身有几个根类, NSObjectNSProxyObject (ObjC 1.0中的Protocol的根类)。

最初的Objective-C语言是非常灵活的,理论上有人可以创build自己的根类,创build自己的框架,完全不同于基础,并使用完全不同于retainreleaseallocdealloc等方法。如果他愿意,甚至可以实施一种完全不同的内存pipe理方式。 这种灵活性对于纯粹的Objective-C语言来说非常惊人 – 它只是提供了一个薄层,所有其他的东西,比如对象的创build和销毁,内存pipe理等等,都可以由用户来决定坐在上面的框架。

但是,对于Apple的Objective-C 2.0和现代运行时,需要做更多的工作来创build自己的根类。 加上ARC,为了在ARC中使用你的对象,你必须实现Cocoa的内存pipe理方法,比如retainrelease 。 另外,为了在Cocoa集合中使用你的对象,你的类还必须实现诸如isEqual:hash类的东西。

所以在现代的Cocoa / Cocoa Touch开发中,对象通常必须至less实现一组基本的方法,它们是NSObject协议中的方法。 Cocoa中的所有根类( NSObjectNSProxy )都实现NSObject协议。

那么,这是怎么回事? Swift类没有定义的超类,只是构成适当根类的NSObject而已? 或者是为每个新的根类别重复默认的对象行为? 还是他们创造了另一个Swift的基类?

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

使用Objective-C运行时,您可以发现对于Swift中的根类的类,从Objective-C的angular度来看,它实际上有一个名为SwiftObject的超类。 而这个SwiftObject类实现NSObject协议的方法,如retainreleaseisEqual:respondsToSelector:等等(尽pipe它实际上并不符合NSObject协议)。 这就是你可以毫无问题地使用纯C ++ API的Swift对象。

但是,从Swift本身,编译器不相信Swift根类实现了这些方法。 所以如果你定义了一个根类Foo ,那么如果你尝试调用Foo().isKindOfClass(Foo.self) ,它将不会编译它,抱怨这个方法不存在。 但是我们仍然可以使用它 – 回想一下,编译器会让我们调用任何types为AnyObject的variables的Objective-C方法(编译器听说过),并且方法查找会产生一个隐式解包的可选函数在运行时成功或失败。 所以我们可以将其AnyObjectAnyObject ,确保导入FoundationObjectiveC (所以声明对编译器是可见的),然后我们可以调用它,它将在运行时工作:

 (Foo() as AnyObject).isKindOfClass(Foo.self) 

所以基本上,从Objective-C的angular度来看,Swift类有一个现有的Objective-C类作为根类(如果它inheritance自Objective-C类),或者有SwiftObject作为根类。

这主要是一个devise决定 ,有一些根类的语言(如Java)和不是的语言(如C ++)。

请注意,在Obj-C中,根类没有被强制执行。 您可以轻松创build一个不从任何类inheritance的对象。 您也可以创build自己的根类,在Apple API( NSObjectNSProxy和弃用Object )中至less有3个。

有一个根类的原因大多是历史的 – 根类保证所有的对象都有一些通用的接口,一些常用的方法(例如isEqualTo:hash()等)是集合类工作所必需的。

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

自从ARC以来,在NSObjectretainrelease并不重要。 有了MRC,你仍然需要给他们打电话。 使用ARC,您绝对不会明确地调用这些方法,并且可以在后台更高效地执行它们。

在Swift中,来自NSObject的方法已经被分成协议 – EquatableHashablePrintableDebugPrintable 。 这样做的好处是对象可以与结构体共享接口。

但是,没有什么能阻止你从NSObjectinheritance每个类。 该类仍然存在,如果您正在处理Obj-C API,则该类特别有用。 在纯粹的Swift中,根类不是必需的。

还有一点注意:

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