Swift Subclasses Used in Generics Don't Get Called When Inheriting from Nsobject

swift subclasses used in generics don't get called when inheriting from NSObject

I was able to confirm your results and submitted it as a bug, https://bugs.swift.org/browse/SR-10617. Turns out this is a known issue! I was informed (by good old Hamish) that I was duplicating https://bugs.swift.org/browse/SR-10285.

In my bug submission, I created a clean compact reduction of your example, suitable for sending to Apple:

protocol P {
init()
func doThing()
}

class Wrapper<T:P> {
func go() {
T().doThing()
}
}

class A : NSObject, P {
required override init() {}
func doThing() {
print("A")
}
}

class B : A {
required override init() {}
override func doThing() {
print("B")
}
}

Wrapper<B>().go()

On Xcode 9.2, we get "B". On Xcode 10.2, we get "A". That alone is enough to warrant a bug report.

In my report I listed three ways to work around the issue, all of which confirm that this is a bug (because none of them should make any difference):

  • make the generic parameterized type's constraint be A instead of P

  • or, mark the protocol P as @objc

  • or, don't have A inherit from NSObject


UPDATE: And it turns out (from Apple's own release notes) there's yet another way:

  • mark A's init as @nonobjc

Should I always inherit from NSObject in Swift classes not to lose certain capabilities

In order to be useable by contains your class must implement the protocol Equatable. When you inherit from NSObject, this is implemented for you. If you want to do it yourself you can do something like:

func == (lhs: B, rhs: B) -> Bool {
return lhs === rhs
}

class B : Equatable {
}

See more about Equatable here: https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/Equatable.html

Why in swift we cannot adopt a protocol without inheritance a class from NSObject?

NSURLConnectionDataDelegate itself inherits from NSURLConnectionDelegate which inherits from NSObjectProtocol.

That means that apart from implementing all the methods from NSURLConnectionDataDelegate, and NSURLConnectionDelegate, you also have to implement all the methods from NSObjectProtocol (e.g. equality, hash).

You didn't implement them, that's your mistake. If you inherit from NSObject, all that NSObjectProtocol methods are already implemented for you.

Swift delegate does not inherit NSObject

You are confusing class NSObject (NSObject class) and protocol NSObject (NSObject protocol, in Swift called NSObjectProtocol).

UINavigationControllerDelegate is a protocol and cannot inherit from class NSObject, it inherits from NSObjectProtocol (switch your documentation to Swift, you will see the difference).

Swift Compiler Error when overriding function of subclass inheriting from NSObject that is declared within a function

This seems like it was a bug in the older versions of Swift. I have tested again in Swift 2.0 and it is now fixed

Swift 3: subclassing NSObject or not?

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



Related Topics



Leave a reply



Submit