Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"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?

like image 448
meaning-matters Avatar asked Aug 26 '16 12:08

meaning-matters


3 Answers

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

like image 117
matt Avatar answered Nov 19 '22 08:11

matt


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.

like image 37
Grimxn Avatar answered Nov 19 '22 08:11

Grimxn


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
like image 44
Farhad Faramarzi Avatar answered Nov 19 '22 07:11

Farhad Faramarzi