一尘不染

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

swift

该文件说

注意

Swift类不能从通用基类继承。您定义而未指定超类的类将自动成为您要构建的基类。”

摘录自:Apple Inc.“ Swift编程语言。” iBooks。

这对我来说没有多大意义。Objective-
C具有通用基类是有原因的,并且同样的原因也适用于Swift,是吗?NSObject管理着保留/释放语义,对默认的实现isEqual:hashdescription。所有这些功能在Swift中也可用。

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

那么,这是怎么回事?没有定义超类的Swift类是否只是NSObject在幕后构成适当的根类的?还是为每个新的根类重复默认的对象行为?还是他们创建了另一个Swift基类?的实施retainrelease是非常复杂的,因为它需要采取多线程和弱引用考虑在同一时间。

Swift中可能有一个通用的基类(尽管文档说了什么)?这真的很方便,因为在Objective-C中,我可以编写一些扩展,使我[obj.eventuallyupdateCounter]可以将方法调用合并到主运行循环中,例如可以将其读取为“-updateCounter下次主运行循环得到控制时调用。如果在此期间,我再次调用此方法,无论如何应该只调用一次,有了这个扩展,就可以实现,-[UIViewsetNeedsDisplay]因为[self.eventually display];如果没有通用基类(或者也许,谁知道,这在Swift中将不再可能)。


阅读 329

收藏
2020-07-07

共1个答案

一尘不染

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

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

正如苏尔坦所说,这是不正确的。在Objective-
C中有多个根类,您可以通过不指定超类来定义新的根类。正如Sulthan还提到,可可本身具有若干根类,NSObjectNSProxy,和Object(根类的Protocol在ObjC
1.0)。

原来的Objective-
C语言是非常灵活的,有人在理论上可以一起走,创造了自己的根类,并创建自己的框架,从基础完全不同,使用方法完全不同retainreleaseallocdealloc,等,甚至可以如果他愿意,可以实现一种完全不同的内存管理方式。这种灵活性是裸露的Objective-
C语言如此令人惊奇的事情之一-它仅提供一个薄层,所有其他事情(如对象的创建和销毁方式,内存管理等)都可以由用户确定坐在上面的框架。

但是,使用Apple的Objective-C2.0和现代化的运行时,需要做更多的工作才能创建自己的根类。加上ARC,为了在ARC中使用对象,必须实现Cocoa的内存管理方法,例如retainrelease。另外,要在Cocoa集合中使用对象,您的类还必须实现isEqual:和这样的东西hash

因此,在现代的Cocoa / CocoaTouch开发中,对象通常至少必须实现一组基本方法,即NSObject协议中的方法。Cocoa(NSObjectNSProxy)中的所有根类均实现该NSObject协议。

那么,这是怎么回事?没有定义超类的Swift类仅仅是NSObjects,它们在后台构成了正确的根类吗?还是为每个新的根类重复默认的对象行为?还是他们创建了另一个Swift基类?

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

通过使用Objective-C运行时,您可以发现,对于一个作为Swift中根类的类,从Objective-
C的角度来看,它实际上有一个名为的超类SwiftObject。而这个SwiftObject类实现的方法NSObject类似协议retainreleaseisEqual:respondsToSelector:,等(虽然它实际上并不符合NSObject协议)。这样便可以毫无问题地将纯Swift对象与Cocoa
API结合使用。

但是,从Swift本身内部,编译器并不认为Swift根类会实现这些方法。因此,如果您定义根类Foo,则尝试调用时Foo().isKindOfClass(Foo.self),它会抱怨该方法不存在而不会对其进行编译。但是我们仍然可以使用它来技巧-回忆一下,编译器将让我们对type变量调用任何Objective-
C方法(编译器已经听说过)AnyObject,并且方法查找会产生一个隐式解包的可选函数,该函数在运行时成功或失败。因此,我们可以将其强制转换为AnyObject,确保导入FoundationObjectiveC(这样声明对编译器可见),然后可以调用它,它将在运行时运行:

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

因此,从Objective-C的角度来看,基本上,Swift类要么具有一个现有的Objective-C类作为根类(如果它是从Objective-C类继承的),要么具有一个SwiftObject根类。

2020-07-07