Why is there no universal base class in Swift?
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.
Root class of all classes in 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.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html
Is that what you were looking for? :)
Extend a functionality for whole the classes
Your question is not clear but guessing I think you wish to be able to extend all classes in your program as you might in, say Objective-C, the equivalent does not exist in Swift.
In Objective-C/Cocoa the vast majority of classes[1] derive directly, or through ancestors, from the NSObject
class - NSObject
is called a base class (often used in relation to Objective-C & Swift) or a root class (often used in relation to Java and C#). By using an Objective-C category you can add methods to NSObject
which are then inherited by all its subclasses.
Java and C#, among others, are languages which like Objective-C have a root class – Object
& System.Object
respectively.
Swift and the Swift Standard Library do not have a single base class, a class may be declared to inherit from a superclass but if no superclass is specified the class is a base class. Given there is no common base class there is no class you can extend which would result in methods being added to all types.
The Swift types Any
, AnyObject
and AnyClass
are not class types and do not represent a base class. AnyClass
is a metatype, that is the type of a type, and as your error messages says Swift does not support extension of metatypes.
HTH
[1] Objective-C itself does not define a common base class, in that way it is similar to Swift. However the primary (Apple) Cocoa framework does, in this it differs from the Swift Standard Library which does not.
Swift native base class or NSObject
Swift classes that are subclasses of NSObject:
- are Objective-C classes themselves
- use
objc_msgSend()
for calls to (most of) their methods - provide Objective-C runtime metadata for (most of) their method implementations
Swift classes that are not subclasses of NSObject:
- are Objective-C classes, but implement only a handful of methods for NSObject compatibility
- do not use
objc_msgSend()
for calls to their methods (by default) - do not provide Objective-C runtime metadata for their method implementations (by default)
Subclassing NSObject in Swift gets you Objective-C runtime flexibility but also Objective-C performance. Avoiding NSObject can improve performance if you don't need Objective-C's flexibility.
Edit:
With Xcode 6 beta 6, the dynamic attribute appears. This allows us to instruct Swift that a method should use dynamic dispatch, and will therefore support interception.
public dynamic func foobar() -> AnyObject {
}
Is there an Object class in Swift?
As explained in "Why is there no universal base class in Swift?", no, but there is a common protocol that every type implicitly conforms to: Any
.
// A statically typed `Any` constant, that points to a value which
// has a runtime type of `Int`
let something: Any = 5
// An array of `Any` things
let things: [Any] = [1, "string", false]
for thing in things {
switch thing {
case let i as Int: consumeInt(i)
case let s as String: consumeString(s)
case let b as Bool: consumeBool(b)
// Because `Any` really does mean ANY type, the compiler can't prove
// that this switch is exhaustive, unless we have a `default`
default: fatalError("Got an unexpected type!")
}
}
However, using Any
is ill-advised most of the time. For most purposes, discriminated unions are a better choice, which Swift has in the form of enums. These ensure that all possible types are considered:
// Using an enum with associated values creates a discriminated union
// containing the exact set of type that we wish to support, rather than `Any`
enum SomeValue { // Note: this is a bad name, but just as an example!
case int(Int)
case string(String)
case bool(Bool)
}
let someValues: [SomeValue] = [.int(1), .string("string"), .bool(false)]
for value in someValues {
switch value {
case .int(let i): consumeInt(i)
case .string(let s): consumeString(s)
case .bool(let b): consumeBool(b)
// Enums have finitely many cases, all of which we exhausted here
// No `default` case required!
}
}
Determine if base class subroutine has been overridden from the base class
my $is_overridden = $self->can("who") != Parent->can("who");
See the documentation for the UNIVERSAL
package, which defines can
.
Also, I should add on a more philosophical note - it sounds like your overriding is violating the Liskov Subsitution Principle, it would probably be better to refactor things so that overriding a method isn't something you have to investigate elsewhere in the code.
Related Topics
How to Use Indices.Contains() in a Collection Extension in Swift 3
How to Create Custom Notifications in Swift 3
Uicollectionview - Resizing Cells on Device Rotate - Swift
Dynamic Row Hight Containing Texteditor Inside a List in Swiftui
Obervableobject Being Init Multiple Time, and Not Refreshing My View
Check Whether Swift Object Is an Instance of a Given Metatype
How to Get the Index of the Element in the List in Swiftui When the List Is Populated with the Array
Arkit - How to Export Obj from Iphone/iPad with Lidar
Swift: Overriding == in Subclass Results Invocation of == in Superclass Only
Firebase Converting Snapshot Value to Objects
Reasons to Include Function in Protocol Definition VS. Only Defining It in the Extension
How to Create Swift Class for Category
Padding a Swift String for Printing
Draw on a PDF Using Swift on MACos
Simpliest Solution to Check If File Exists on a Webserver. (Swift)
Xcode 9 and Xcode 10 Giving Different Results, Even with Same Swift Version