Home > other >  How to override readonly property in Swift subclass, make it read-write, and assign to superclass?
How to override readonly property in Swift subclass, make it read-write, and assign to superclass?

Time:06-11

How can I override readonly property of a Swift superclass, from a subclass, to make the property read-write?

I want to do that, because that is what the iOS UIResponder documentation says is required. However, I'm getting an error when I try to implement what I think the Swift 5 documentation says can be done:

Swift 5 documentation

Inheritance

Overriding Property Getters and Setters:
You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override.

What Went Wrong:

Based on aforementioned Swift docs statement, for which I found no accompanying example, I created the following subclass, at which XCode generates this error message:

   "Cannot assign to property: 'inputAccessoryViewController' is a get-only property"

My Subclass:

class InputAccessoryEnabledTextView : UITextView {
    override var inputAccessoryViewController: UIInputViewController? {
        get { super.inputAccessoryViewController }
        set { super.inputAccessoryViewController = newValue }
    }
}

UIResponder

Declaration

var inputAccessoryViewController: UIInputViewController? { get }

Discussion

This property is typically used to attach an accessory view controller to the system-supplied keyboard that is presented for UITextField and UITextView objects. The value of this read-only property is nil. If you want to attach custom controls to a system-supplied input view controller (such as the system keyboard) or to a custom input view (one you provide in the inputViewController property), redeclare this property as read-write in a UIResponder subclass. You can then use this property to manage a custom accessory view. When the receiver becomes the first responder, the responder infrastructure attaches the accessory view to the appropriate input view before displaying it.

Note: I do see a question from 6 years ago on Stack Overflow that got no accepted answers and doesn't seem to properly answer the question, so please don't flag this as a dup without a good reason. Perhaps these questions can be merged later

CodePudding user response:

super.inputAccessoryViewController is not settable.

Your overridden implementation in the subclass, self.inputAccessoryViewController is.

By adding a setter to the property in a subclass, you don't automatically also add the same thing in the superclass. What's in the subclass stays in the subclass.

So it's not that you can't override a property by adding a setter, you just can't set this here:

override var inputAccessoryViewController: UIInputViewController? {
    get { super.inputAccessoryViewController }
    set { super.inputAccessoryViewController = newValue }
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

You can do other things, like:

override var inputAccessoryViewController: UIInputViewController? {
    get { super.inputAccessoryViewController }
    set { print("I just go set to \(newValue)") }
}

But that's not very useful. What you want is probably:

private var myInputAccessoryController: UIInputViewController?

override var inputAccessoryViewController: UIInputViewController? {
    get { myInputAccessoryController }
    set { myInputAccessoryController = newValue }
}
  • Related