I have a subclass whose inheritance chain breaks down to look like this:
InputAccessoryEnabledTextField : UITextField : UIControl : UIView : UIResponder
InputAccessoryEnabledTextField provides an override:
private var myInputAccessoryController: UIInputViewController?
override var inputAccessoryViewController: UIInputViewController? {
get { myInputAccessoryController }
set { myInputAccessoryController = newValue }
}
The code above, working as the solution I was seeking, is from the accepted answer (@Sweeper) to a question I just asked on S.O. It is overriding an instance property of UIResponder.
However, it doesn't make sense to me. How can/does it work?
How is it possible that UITextField
, superclass to my subclass, honors an override provided my subclass (InputAccessoryEnabledTextField
)?
Doesn't that violate the inheritance hierarchy? Shouldn't only subclasses of InputAccessoryEnabledTextField
be able to see its override, not superclasses?
Or do overrides apply to the whole object, such that every inherited superclass sees the state of some arbitrary outermost subclass? Or, is it that the iOS text subsystem is doing some really convoluted stuff?
Maybe this is too abstract a question for S.O. and I don't mind closing or deleting it, Just posting this to avoid a 'dialog' in the comments that the bot complains about.
(The example below proves @RobNapier correct, which I initially confirmed by successfully overriding UIResponder.inputAccessoryViewController
and observing my viewController activated when the keyboard pops up for my subclassed UITextView : UIResponder
)
The Good:
Swift overrides as explained by @RobNaipier in comments, make sense, at least from certain points of view. And can obviously be exploited for its interesting flexibility
The Bad:
However, it isn't what I assumed, and I was somewhat stunned that inheritance works that way, because intuitively I realized that letting subclasses tamper with superclasses` view of themselves is potentially risky, especially if one doesn't know superclass implementation details (as is the case with UIKits proprietary implementation code Apple doesn't release the source to the public).
The Ugly:
So while Swift inheritance lets the inheritors achieve tweak things for interesting or useful effect, and could be very handy in some cases, in practical use, for example with UIKit, it does leads to anticipated problems and confusion.
The coup de grâce, which I'm grateful that Rob pointed out, is that, due to the anticipated downsides, class inheritance with UIKit is increasingly discouraged by Apple and struct+protocol has been adopted by SwiftUI.
class TheSuperclass {
var x = 5
init() {
print("How superclass sees it before subclass initialized: x = \(x)")
}
func howSuperclassSeesItselfAfterSubclassInit() {
print("How superclass sees it after subclass initialized: x = \(x)")
}
}
class TheSubclass : TheSuperclass {
override var x : Int {
get { super.x + 10 }
set { super.x = newValue }
}
override init() {
super.init()
print("How subclass sees it after superclass" +
"initialized: x = \(x), super.x = \(super.x)")
}
}
TheSubclass().howSuperclassSeesItselfAfterSubclassInit()
The above code when run in Playground displays the following:
How superclass sees it before subclass initialized: x = 5 How subclass sees it after superclass initialized: x = 15, super.x = 5 How superclass sees it after subclass initialized: x = 15