Search code examples
swiftgenericsprotocols

weak property conforming to protocol with generic constraint


I wrote simplified version of similar implementation I'm having problem with. Anyone knows why is that and eventually how to workaround?

NOTE: the code is just example to keep it as simple as possible

protocol Alertable {
   associatedtype Alert

   func show(alertOfType alertType: Alert)
}
protocol ViewControllerDelegate: class, Alertable {
}

final class MyViewController: UIViewController {

   // MARK: - Types

   enum AlertType {
      case alert
      case warning
   }
}

extension MyViewController: ViewControllerDelegate {
   typealias Alert = AlertType   // ! here i specify the associated type !

   func show(alertOfType alertType: Alert) {
      // code..
   }
}

So far so good. But, here I get errors:

final class ViewModel {

   // ERROR: Protocol 'ViewControllerDelegate' can only be used as a generic constraint because it has Self or associated type requirements.
   weak var viewController: ViewControllerDelegate?

   init(viewController: ViewControllerDelegate?) {
      self.viewController = viewController
   }

   private func someFunction() {

      // ERROR: Member 'show' cannot be used on value of protocol type 'NewsFeedViewControllerInput'; use a generic constraint instead.
      viewController?.show(alertOfType: .warning)

      // code..
   }
}

Thank you


Solution

  • You had a bit of a misunderstanding here. When you define:

    protocol ViewControllerDelegate: class, Alertable {}
    
    extension MyViewController: ViewControllerDelegate {
        typealias Alert = AlertType   // ! here i specify the associated type !
    
        func show(alertOfType alertType: Alert) {
            // code..
        }
    }
    

    The typealias is defined in MyViewController but not ViewControllerDelegate. It's not clear why you need ViewControllerDelegate in this question but maybe there's something we don't see in the real app.

    In ViewModel, change from ViewControllerDelegate to MyViewController:

    final class ViewModel {
        weak var viewController: MyViewController?
        // ...
    }
    

    One more thing, though unrelated to the error: you use many final classes. Should they be structs instead?