问题描述
文档说
注意
Swift 类不从通用基类继承.给你上课定义而不指定超类自动成为基类供您构建的类."
Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon."
摘自:Apple Inc.Swift 编程语言." iBooks.
Excerpt From: Apple Inc. "The Swift Programming Language." iBooks.
这对我来说没有多大意义.Objective-C 有一个通用基类是有原因的,同样的原因应该适用于 Swift,是吗?NSObject
管理保留/释放语义,这是 isEqual:
、hash
和 description
的默认实现.所有这些功能也可以在 Swift 中使用.
It doesn't make much sense to me. There is a reason why Objective-C has a universal base class, and the same reason should apply to Swift, does it? NSObject
manages retain/release semantics, a default implementation for isEqual:
, hash
and description
. All this functionality is available in Swift too.
(Objective-C 和 Swift 使用相同的运行时...)
(Objective-C and Swift use the same runtime...)
所以,这是怎么回事?没有定义超类的 Swift 类是否只是 NSObject
,它们在幕后伪装成适当的根类?还是每个新的根类都复制了默认的对象行为?或者他们创建了另一个 Swift 基类?retain
和 release
的实现真的很复杂,因为它需要同时考虑多线程和弱引用.
So, what's up with that? Are Swift classes with no defined superclasses just NSObject
s that pose as proper root classes under the hood? Or is the default object-behaviour duplicated for each new root-class? Or have they created another Swift-baseclass? The implementation of retain
and release
is really complex, because it needs to take multithreading and weak references into account at the same time.
Swift 中是否有通用基类(尽管文档中有说明)?这真的很方便,因为在 Objective-C 中,我可以例如编写扩展,让我可以将方法调用合并到主 runloop 中,例如 [obj.eventually updateCounter]
可以读为call -updateCounter
下次主 runloop 进入时控件.如果同时,我再次调用此方法,无论如何它应该只调用一次.使用此扩展,可以将 -[UIView setNeedsDisplay]
实现为 [self.eventually display];
如果没有通用基类,这在 Swift 中将不再可能(或者可能是,谁知道?)
Is there maybe a universal base class in Swift (despite what the documentation says)? It would be really handy, because in Objective-C I can e.g. write extensions that let me coalesce method invocations to the main runloop like [obj.eventually updateCounter]
which can be read as "call -updateCounter
the next time the main runloop gets in control. If, in the meantime, I call this method again, it should be called only once anyways. With this extension one could implement -[UIView setNeedsDisplay]
as [self.eventually display];
This is no longer possible in Swift if there is no universal base class (or maybe it is, who knows?)
推荐答案
有几种面向对象的语言可以定义新的根类,包括 C++、PHP 和 Objective-C,它们工作得很好,所以这是绝对不是什么特别的东西.
There are several object-oriented languages where one can define new root classes, including C++, PHP, and Objective-C, and they work fine, so this is definitely not a special thing.
Objective-C 有一个通用基类是有原因的
正如 Sulthan 所说,这不是真的.Objective-C 中有多个根类,您可以通过简单地不指定超类来定义一个新的根类.正如 Sulthan 也提到的,Cocoa 本身有几个根类,NSObject
、NSProxy
和 Object
(Protocol
的根类)代码>在ObjC 1.0).
As Sulthan mentioned, this is not true. There are multiple root classes in Objective-C, and you can define a new root class by simply not specifying a superclass. As Sulthan also mentioned, Cocoa itself has several root classes, NSObject
, NSProxy
, and Object
(the root class of Protocol
in ObjC 1.0).
最初的Objective-C语言非常灵活,理论上有人可以创建自己的根类,创建自己的与Foundation完全不同的框架,使用与retain
、release
、alloc
、dealloc
等,如果他愿意,甚至可以实现完全不同的内存管理方式.这种灵活性是裸Objective-C语言令人惊奇的地方之一——它只是提供了一个薄层,所有其他的事情,比如对象如何创建和销毁,内存管理等,都可以由用户决定框架位于顶部.
The original Objective-C language was very flexible and someone could in theory come along and create his own root class and create his own framework that is completely different from Foundation, and uses methods completely different from retain
, release
, alloc
, dealloc
, etc., and could even implement a completely different way of memory management if he wanted. This flexibility is one of the things so amazing about the bare Objective-C language -- it simply provides a thin layer, all the other things like how objects are created and destroyed, memory management, etc., can all be determined by the user frameworks sitting on top.
但是,使用 Apple 的 Objective-C 2.0 和现代运行时,需要做更多的工作来制作你自己的根类.并且随着ARC的加入,为了在ARC中使用你的对象,你必须实现Cocoa的内存管理方法,比如retain
和release
.此外,要在 Cocoa 集合中使用您的对象,您的类还必须实现诸如 isEqual:
和 hash
之类的东西.
However, with Apple's Objective-C 2.0 and modern runtime, more work needed to be done to make your own root class. And with the addition of ARC, in order to use your objects in ARC, you must implement Cocoa's memory management methods like retain
and release
. Also, to use your objects in Cocoa collections, your class must also implement things like isEqual:
and hash
.
所以在现代Cocoa/Cocoa Touch开发中,对象一般至少要实现一套基本的方法,也就是NSObject
协议中的方法.Cocoa 中的所有根类(NSObject
、NSProxy
)都实现了 NSObject
协议.
So in modern Cocoa/Cocoa Touch development, objects generally must at least implement a basic set of methods, which are the methods in the NSObject
protocol. All the root classes in Cocoa (NSObject
, NSProxy
) implement the NSObject
protocol.
所以,这是怎么回事?是没有定义的 Swift 类超类只是作为适当根类的 NSObjects兜帽?或者是为每个新对象复制了默认的对象行为根类?还是他们创建了另一个 Swift 基类?
这是一个很好的问题,您可以通过使用 Objective-C 运行时进行自省.在某种意义上,Swift 中的所有对象也是 Objective-C 对象,因为它们可以像 Objective-C 中的对象一样与 Objective-C 运行时一起使用.类的某些成员(未标记 @objc
或 dynamic
的成员)可能对 Objective-C 不可见,但在其他情况下,Objective-C 运行时的所有内省功能完全处理纯 Swift 类的对象.在 Swift 中定义的类对于 Objective-C 运行时来说看起来就像任何其他类,只是名称被修改了.
This is a good question, and you can find out by introspection with the Objective-C runtime. All objects in Swift are, in a sense, also Objective-C objects, in that they can be used with the Objective-C runtime just like objects from Objective-C. Some members of the class (the ones not marked @objc
or dynamic
) may not be visible to Objective-C, but otherwise all the introspection features of the Objective-C runtime work fully on objects of pure Swift classes. Classes defined in Swift look like any other class to the Objective-C runtime, except the name is mangled.
使用Objective-C运行时,你可以发现对于一个在Swift中是根类的类,从Objective-C的角度来看,它实际上有一个名为SwiftObject
的超类.而这个 SwiftObject
类实现了 NSObject
协议的方法,如 retain
、release
、isEqual:
、respondsToSelector:
等(虽然它实际上并不符合 NSObject
协议).这就是您可以毫无问题地将纯 Swift 对象与 Cocoa API 结合使用的方法.
Using the Objective-C runtime, you can discover that for a class that is a root class in Swift, from the point of view of Objective-C, it actually has a superclass named SwiftObject
. And this SwiftObject
class implements the methods of the NSObject
protocol like retain
, release
, isEqual:
, respondsToSelector:
, etc. (though it does not actually conform to the NSObject
protocol). This is how you can use pure Swift objects with Cocoa APIs without problem.
然而,从 Swift 本身内部来看,编译器并不相信 Swift 根类实现了这些方法.因此,如果您定义了一个根类 Foo
,那么如果您尝试调用 Foo().isKindOfClass(Foo.self)
,它不会编译它抱怨此方法确实不存在.但是我们仍然可以通过一个技巧来使用它——回想一下,编译器会让我们在 AnyObject
类型的变量上调用任何 Objective-C 方法(编译器听说过),以及方法查找产生一个在运行时成功或失败的隐式解包可选函数.所以我们可以做的是强制转换为 AnyObject
,确保导入 Foundation
或 ObjectiveC
(这样声明对编译器是可见的),我们然后可以调用它,它会在运行时工作:
From inside Swift itself, however, the compiler does not believe that a Swift root class implements these methods. So if you define a root class Foo
, then if you try to call Foo().isKindOfClass(Foo.self)
, it will not compile it complaining that this method does not exist. But we can still use it with a trick -- recall that the compiler will let us call any Objective-C method (which the compiler has heard of) on a variable of type AnyObject
, and the method lookup produces an implicitly-unwrapped optional function that succeeds or fails at runtime. So what we can do is cast to AnyObject
, make sure to import Foundation
or ObjectiveC
(so the declaration is visible to the compiler), we can then call it, and it will work at runtime:
(Foo() as AnyObject).isKindOfClass(Foo.self)
所以基本上,从 Objective-C 的角度来看,Swift 类要么具有现有的 Objective-C 类作为根类(如果它继承自 Objective-C 类),要么具有 SwiftObject
作为根类.
So basically, from the Objective-C point of view, a Swift class either has an existing Objective-C class as root class (if it inherited from an Objective-C class), or has SwiftObject
as root class.
这篇关于为什么 Swift 中没有通用基类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!