tacos_tacos_tacos
tacos_tacos_tacos

Reputation: 10585

Why must I keep declaring the same required but not implemented initializer for init(coder aDecoder) for my programatic UIViewController subclass?

Perhaps it is just me, but I find certain aspects of swift... obtuse to say the least.

I don't use Interface Builder most of the time because I like using PureLayout. So I was hoping to make a UIViewController subclass, say PureViewController, that had a handy init without parameters:

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

}

But this is not okay, for XCode tells me I must also implement init(coder aDecoder: NSCoder). Okay, that's fine! That's why I made this class - so I don't have to do this again for subclasses.

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Ok, now here's what I don't get.

I define a subclass, SomePureViewController : PureViewController, with an initializer init(viewModel:ICrackersViewModel)...

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

}

But it STILL wants me to define the same stupid initializer till kingdom come!

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Now I understand the idea - there is no init(decoder) in my subclass, even though it is defined in its parent class.

Maybe I've always dealt with this issue with UIViewController and never noticed it before.

My questions are as follows:

  1. Is there something I am doing wrong to cause this behavior?
  2. Is there any way outside of inheritance that I can avoid repeating myself?
  3. Are there plans to any plans to change this?

Upvotes: 4

Views: 631

Answers (3)

eik
eik

Reputation: 4610

The point is that one can initialize a possibly derived class just by knowing the base type.

Lets assume a base class

class Base {
    let value: Int

    required init(value: Int) {
        self.value = value
    }
}

and a function

func instantiateWith5(cls: Base.Type) -> Base {
    return cls.init(value: 5)
}

then we can do

let object = instantiateWith5(Base.self)

Now if someone defines a derived class

class Derived: Base {
    let otherValue: Int

    init() {
        otherValue = 1
        super.init(value: 1)
    }

    required init(value: Int) {
        fatalError("init(value:) has not been implemented")
    }
}

We are at least able to call

let object2 = instantiateWith5(Derived.self)

violating LSP, but that's a problem of your code, not the language.

Swift has to guarantee that initializers leave your objects in a initialized state, even when they are derived from a base object, so I guess changing that would be a bad thing. If you like to define a UIViewController that is not deserializable and thereby violating LSP it's your decision - but don't expect the language to support you in this.

Upvotes: 2

Paulw11
Paulw11

Reputation: 114975

As the initialiser is marked with the required keyword, all subclasses must implement that initialiser and they must also specify required on their implementation so that their subclasses are also required to implement it.

Required Initializers

Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer

You must also write the required modifier before every subclass implementation of a required initializer, to indicate that the initializer requirement applies to further subclasses in the chain.”

This has been part of the Swift language since 1.0 and it is unlikely to change.

The issue is actually to do with the use of the required keyword in the UIViewController class definition. In theory this could be changed, but again I think it is unlikely.

Upvotes: 1

Deny
Deny

Reputation: 1461

I think that this is swift issue and there is no way how to avoid this. We all hate this empty - fatal error initializer.

Upvotes: 1

Related Questions