meaning-matters
meaning-matters

Reputation: 23006

"Ambiguous reference to member 'init(...)" calling baseclass initializer

I have a baseclass:

class ViewController: UIViewController
{
    init(nibName nibNameOrNil: String?)
    {
        super.init(nibName: nibNameOrNil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) { }
}

a subclass:

class OneViewController: ViewController
{
    private var one: One
    init(one: One)
    {
        self.one = one

        super.init(nibName: "OneNib")
    }

    required init?(coder aDecoder: NSCoder) { }
}

and a subclass of the above subclass:

class TwoViewController: OneViewController
{
    private var two: Two
    init(two: Two)
    {
        self.two = two

        super.init(nibName: "TwoNib") <== ERROR
    }

    required init?(coder aDecoder: NSCoder) { }
}

At the indicated line I get the error:

Ambiguous reference to member 'init(one:)'

I don't understand why the compiler can't figure out I'm referring to ViewController's init(), like it managed to do in One's init().

What am I missing and/or doing wrong?

Upvotes: 8

Views: 6367

Answers (3)

Grimxn
Grimxn

Reputation: 22517

The chapter in the Swift manual on Designated Initializers will clarify it, but basically OneViewController has only one way to set self.one, and that's by initialising using init(one: One). You cannot bypass that, which is what you are trying to do.

  • If what you were trying to do could succeed, what value would two.one have in the following?

    let two = Two(two: SomeTwo)
    print(two.one)
    
  • Answer - undefined. That's why it isn't allowed.

Having declared One.init(one:) it is now the Designated Initializer, and there's no way to go round it.

Upvotes: 3

matt
matt

Reputation: 536027

I don't understand why the compiler can't figure out I'm referring to ViewController's init(), like it managed to do in One's init()

It is because, from inside TwoViewController, the compiler can't see ViewController's init. The rule is:

As soon as you implement a designated initializer, you block inheritance of initializers.

Therefore, OneViewController has only one initializer, namely init(one:). Therefore, that is the only super initializer that TwoViewController can call.

If you want ViewController's init(nibName:) to be present in OneViewController, you must implement it in OneViewController (even if all it does is to call super).

Upvotes: 8

Farhad Faramarzi
Farhad Faramarzi

Reputation: 465

you don't necessary pass value into constructor's ViewController . you can define public object in oneViewController and you access of outer .

 class OneViewController: ViewController {
    public var one: One

 }


let vc = storyboard?.instantiateViewControllerWithIdentifier("OneViewController") as OneViewController

let one = One()
vc.one = one

Upvotes: 1

Related Questions