文档说
请注意
Swift类不从通用基类继承。给你上课 定义而不指定超类自动成为基类 你可以上课。“
摘自:Apple Inc.“The Swift Programming Language.”iBooks。
对我来说没有多大意义。 Objective-C有一个普遍的基类是有原因的,同样的理由应该适用于Swift,是吗? NSObject
管理保留/释放语义,isEqual:
,hash
和description
的默认实现。所有这些功能也可以在Swift中使用。
(Objective-C和Swift使用相同的运行时...)
那么,那是什么呢? Swift类没有定义的超类只是NSObject
s,它们构成了引擎盖下的正确根类吗?或者是每个新的根类重复的默认对象行为?或者他们创建了另一个Swift-baseclass? retain
和release
的实现非常复杂,因为它需要同时考虑多线程和弱引用。
Swift中是否有通用基类(尽管文档中有说明)?这将非常方便,因为在Objective-C中我可以例如编写扩展,让我将方法调用合并到主要的runloop,如[obj.eventually updateCounter]
,可以读作"下次主runloop控制时调用-updateCounter
。如果在此期间我再次调用此方法,则应该只调用一次。使用此扩展,可以将-[UIView setNeedsDisplay]
实现为[self.eventually display];
如果没有通用基类(或者可能是谁,谁知道?),这在Swift中不再可能。
答案 0 :(得分:40)
有几种面向对象的语言可以定义新的根类,包括C ++,PHP和Objective-C,它们工作正常,所以这绝对不是特别的事。
Objective-C有一个通用基类
的原因
正如Sulthan所说,这不是真的。 Objective-C中有多个根类,您只需不指定超类就可以定义新的根类。正如Sulthan所提到的,Cocoa本身有几个根类,NSObject
,NSProxy
和Object
(ObjC 1.0中的Protocol
的根类)。
最初的Objective-C语言非常灵活,理论上有人可以创建自己的根类并创建自己的框架,该框架与Foundation完全不同,并使用与retain
完全不同的方法,{ {1}},release
,alloc
等,如果他愿意,甚至可以实现完全不同的内存管理方式。这种灵活性是关于纯粹的Objective-C语言的一个令人惊奇的事情之一 - 它只是提供了一个薄层,所有其他的东西,如对象的创建和销毁,内存管理等等,都可以由用户决定框架坐在上面。
但是,使用Apple的Objective-C 2.0和现代运行时,需要more work来创建自己的根类。通过添加ARC,为了在ARC中使用对象,您必须实现Cocoa的内存管理方法,如dealloc
和retain
。此外,要在Cocoa集合中使用您的对象,您的类还必须实现release
和isEqual:
之类的内容。
因此,在现代Cocoa / Cocoa Touch开发中,对象通常必须至少实现一组基本方法,这些方法是hash
协议中的方法。 Cocoa中的所有根类(NSObject
,NSObject
)都实现了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
协议的方法,如NSObject
,retain
,release
,isEqual:
等等。实际上并不符合respondsToSelector:
协议。这就是如何在没有问题的情况下将纯Swift对象与Cocoa API一起使用。
然而,从Swift内部来看,编译器并不认为Swift根类实现了这些方法。因此,如果您定义根类NSObject
,那么如果您尝试调用Foo
,它将不会编译它抱怨此方法不存在。但是我们仍然可以用一个技巧 - 回想一下,编译器会让我们在Foo().isKindOfClass(Foo.self)
类型的变量上调用任何Objective-C方法(编译器已经听说过),并且方法查找会产生一个隐式的-unwrapped可选功能,在运行时成功或失败。所以我们可以做的是转换为AnyObject
,确保导入AnyObject
或Foundation
(因此声明对编译器是可见的),然后我们可以调用它,它会工作在运行时:
ObjectiveC
基本上,从Objective-C的角度来看,Swift类要么将现有的Objective-C类作为根类(如果它继承自Objective-C类),要么以(Foo() as AnyObject).isKindOfClass(Foo.self)
为根类。
答案 1 :(得分:26)
这主要是设计决策,有些语言具有根类(例如Java)和不具备语言的语言(例如C ++)。
请注意,在Obj-C中,不强制执行根类。您可以轻松创建一个不从任何类继承的对象。您还可以创建自己的根类,Apple API中至少有3个(NSObject
,NSProxy
和已弃用Object
)。
拥有根类的原因主要是历史 - 根类确保所有对象都有一些共同的接口,一些常用的方法(例如isEqualTo:
,hash()
等)是收集所必需的上课。
一旦你有了泛型(或C ++中的模板),拥有根类就不那么重要了。
自{ARC}以来,retain
中的release
和NSObject
不再重要了。使用MRC,您仍然需要打电话给他们。使用ARC,您永远不会明确地调用这些方法,并且可以在幕后更有效地实现它们。
在Swift中,NSObject
中的方法已分为协议 - Equatable
,Hashable
,Printable
和DebugPrintable
。这样做的好处是对象可以与结构共享接口。
然而,没有什么可以阻止你继承NSObject
的每个班级。该类仍然存在,如果您正在处理Obj-C API,它尤其有用。在纯Swift中,根类不是必需的。
还有一点需要注意:
Swift课程并不在Obj-C之上运行;他们没有在幕后翻译成Obj-C。它们只是由相同的编译器编译,允许它们相互操作。理解这一点非常重要。这就是为什么有时必须添加@objc
以提供与Obj-C协议/类的一致性的原因。