32

I'm trying to understand what I'm doing wrong with generics in swift.

I created this sample playground

import UIKit

public protocol MainControllerToModelInterface : class {
    func addGoal()
    init()
}

public protocol MainViewControllerInterface : class {
    associatedtype MODELVIEW
    var modelView: MODELVIEW? {get set}

    init(modelView: MODELVIEW)
}

public class MainViewController<M> : UIViewController, MainViewControllerInterface where M : MainControllerToModelInterface {
    public weak var modelView: M?

    required public init(modelView: M) {
        self.modelView = modelView
        super.init(nibName: String(describing: MainViewController.self), bundle: Bundle.main)
    }

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

public class Other<C, M> : NSObject where C : MainViewControllerInterface, C : UIViewController, M : MainControllerToModelInterface, C.MODELVIEW == M {
    var c : C?

    override init() {
        let m = M()
        self.c = C(modelView: m)
        super.init()
    }
}

the line self.c = C(modelView: m) gives me this error non-nominal type 'C' does not support explicit initialization

From this other stack overflow question I see that this error in older Xcode versions means

cannot invoke initializer for type '%type' with an argument list of type '...' expected an argument list of type '...'

But in the playground above what is the compiler missing?

I'm on swift4/xcode9.

Update

After following the suggestion Use C.init(modelView: m) rather than C(modelView: m) the error changes in:

No 'C.Type.init' candidates produce the expected contextual result type '_?'

Than @vini-app suggested to remove the UIViewController to make it works. By I still don't understand why the compiler is not happy when UIViewController is there. Is it not enough to know that C has that valid init method?

Luca Bartoletti
  • 2,435
  • 1
  • 24
  • 46

3 Answers3

51

You just need to use init explicitly whenever you're initializing a generic parameter rather than a "real" type:

self.c = C.init(modelView: m)
andyvn22
  • 14,696
  • 1
  • 52
  • 74
3

Use C.init(modelView: m) rather than C(modelView: m). That should fix it.

rounak
  • 9,217
  • 3
  • 42
  • 59
1

Please check :

In your code you are doing like this C : MainViewControllerInterface, C : UIViewController.

It is treating C as ViewController, then there is no init in ViewController like init(modelView: M) thats why its throwing error

public class Other<C, M> : NSObject where C : MainViewControllerInterface, M : MainControllerToModelInterface, C.MODELVIEW == M {
    var c : C?

    override init() {
        let m = M()
        self.c = C(modelView: m)
        super.init()
    }
}
Vini App
  • 7,339
  • 2
  • 26
  • 43
  • Thanks, but C is `C : MainViewControllerInterface`. That protocol defines the initializer i’m using there. – Luca Bartoletti Sep 28 '17 at 00:35
  • After deleting ViewController, its working. Please check my code. – Vini App Sep 28 '17 at 00:36
  • Yes, but still, it's like the thing it's that I need that. you say that `It is treating C as ViewController, then there is no init in ViewController like init(modelView: M) thats why its throwing error` but this doesn't make sense to me. C is also adopting `MainViewControllerInterface`, so why is not enough for the compiler? – Luca Bartoletti Sep 28 '17 at 09:17
  • Is because UIViewController is a class and not a protocol? – Luca Bartoletti Sep 28 '17 at 09:44