I have read some posts like this one about the difference between subclassing NSObject
in Swift or just having its native base class
with no subclassing. But they all are a bit old posts, and I am not clear about this topic.
When should you subclass NSObject
? What is the actual difference between subclassing it and not subclassing? What is currently the recommendation in Swift?
That means all UIKit classes ultimately come from NSObject , including all of UIKit. You don't have to inherit from NSObject in Swift, but you did in Objective-C and in fact there are some behaviors you can only have if you do inherit from it.
NSObject exists to mark a class in Swift that you will provide that basic functionality — basically Objective-C needs you to build up from a base class with your functionality on top (That is, NSObject is a Universal Base Class).
The root class of most Objective-C class hierarchies, from which subclasses inherit a basic interface to the runtime system and the ability to behave as Objective-C objects.
Only classes that inherit from NSObject can be declared @objc w/ UIView.
Apple's documentation about NSObject states the following as an introduction:
NSObject is the root class of most Objective-C class hierarchies. Through NSObject, objects inherit a basic interface to the runtime system and the ability to behave as Objective-C objects.
As this would suggest, you need to subclass NSObject for types introduced in your code whenever instances of that type need to behave like an Objective-C object (or the class itself, in some rarer cases).
I am not aware of super explicit Apple provided written guidance on when not to subclass NSObject, beyond suggesting reducing dynamic dispatch or presenting code reuse paradigms using that do not relying on subclassing but protocol extensions, i.e. code reuse that is generally more static dispatch and value type friendly). I believe it is fair to say though that most Swift programmers have taken hints from Apple, and Swift language features as signs to avoid introducing NSObject based types when the above-mentioned need is not there. That is, as a general rule, only introduce NSObject based types when you actually need the Objective-C dynamism, most commonly when you need to interface with Cocoa APIs (especially common when your code is UI related: e.g. view controllers, views).
As pointed out in an answer to the question you link to, with Objective-C style dynamism comes the performance of objc_msgSend
based method dispatch. Although methods in Swift classes are also virtual, the compiler is able to use faster means of dispatching methods when you don't explicitly mark the methods with the @objc
attribute – especially when Whole Module Optimization is toggled on, and even more so in Swift 3 where classes are not by default open for subclassing beyond the module that defines the type.
Beyond avoiding NSObject, you can also avoid class based reference types altogether in many cases when writing Swift. Take a look at for instance the value type WWDC videos linked above, or for example this blog post as an introduction. Briefly, using value types you gain good local reasoning, often avoid dynamic memory allocation and reference counting overhead (though not universally so – structs with reference types as fields being the caveat).
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