The documentation says
NOTE
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.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
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 and Swift use the same runtime...)
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.
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?)
Multiple inheritance is not possible in Swift.
Inheritance allows us to create a new class from an existing class. The new class that is created is known as subclass (child or derived class) and the existing class from which the child class is derived is known as superclass (parent or base class). Here, we are inheriting the Dog subclass from the Animal superclass.
NSObject is The root class of most Objective-C class hierarchies, from which subclasses inherit a basic interface to the runtime system.
This is called class inheritance or subclassing, the class you inherit from is called the “parent” or “super” class, and the new class is called the “child” class. For safety reasons, Swift always makes you call super. init() from child classes – just in case the parent class does some important work when it's created.
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.
There is a reason why Objective-C has a universal base class
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).
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.
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
.
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.
So, what's up with that? Are Swift classes with no defined superclasses just NSObjects 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?
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.
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.
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)
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.
This is mainly a design decision, there are languages which have a root class (e.g. Java) and languages which don't (e.g. C++).
Note that in Obj-C a root class is not enforced. You can easily create an object which doesn't inherit from any class. You can also create your own root classes, there are at least 3 in the Apple API (NSObject
, NSProxy
and deprecated Object
).
The reason to have a root class is mostly historical - the root class ensures that all objects have some common interface, some common methods (e.g. isEqualTo:
, hash()
etc.) which are necessary for collection classes to work.
Once you have generics (or templates in C++), having a root class is not so important any more.
retain
and release
in NSObject
are not important anymore since ARC. With MRC, you were still required to call them. With ARC you never call the methods explicitly and they can be implemented more efficiently behind the scenes.
In Swift, the methods from NSObject
have been divided into protocols - Equatable
, Hashable
, Printable
and DebugPrintable
. That has the advantage that objects can share interfaces with structs.
However, there is nothing stopping you from inheriting every class from NSObject
. The class is still there and it is especially useful if you are dealing with Obj-C APIs. In pure Swift, a root class is not necessary though.
One more note:
Swift classes doesn't run on top of Obj-C; they are not translated into Obj-C behind the scenes. They are just compiled by the same compiler which allows them to interoperate with each other. That's really important to understand. That's why @objc
must be sometimes added to provide consistency with Obj-C protocols/classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With