swiftclassinheritancesubclassnsobject

Swift 3: subclassing NSObject or not?


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?


Solution

  • 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).