iosswiftgenericsviper-architecture

Generics types in VIPER subclassing. Cannot assign value of type 'ChildType' to type 'ParentType<Any>?'


I have VIPER architecture and I want to create parent VIPER search component that works with generic type. The idea is simple so I have search bar and I have table view. For example I can show drinks or foods names in table view. Depends on which generic data type I specified I want to show or foods or drinks.

I found very good example that solves my issue with generic view controllers. But I want to create something similar for swift generic VIPER architecture.

I will skip describing all VIPER classes like (Router, Interdictor and etc).

So I have parent view controller:

BaseSearchViewController: UIViewController {
   var presenter: BaseSearchPresenter<Any>?
}

and child:

FoodSearchViewController: BaseSearchViewController {
}

This is a parent presenter specified in BaseSearchViewController

class BaseSearchPresenter<T> {
    var items [T]
}

also I have child food search presenter with a specific type Food I would like to display in my table:

class FoodSearchPresenter: BaseSearchPresenter<Food> {
}

When I try to configure my VIPER:

let viewController = FoodSearchViewController(...) // init VC
let presenter = FoodSearchPresenter()

viewController.presenter = presenter // assigning child FoodSearchPresenter instance to a BaseSearchViewController presenter variable leads to this error:

Cannot assign value of type 'FoodSearchPresenter' to type 'BaseSearchPresenter<Any>?'

Here is a repo with the issue.


Solution

  • I left comments about how to attack this problem, but to your specific case, the answer is that BaseSearchViewController needs to be generic.

    class BaseSearchPresenter<T> {
        var items: [T] = []
    }
    
    // BaseSearchViewController must be generic in order to vary its Element
    class BaseSearchViewController<Element>: UIViewController {
        var presenter: BaseSearchPresenter<Element>?
    }
    
    struct Food {}
    
    class FoodSearchPresenter: BaseSearchPresenter<Food> {}
    
    class FoodSearchViewController: BaseSearchViewController<Food> {}
    
    let viewController = FoodSearchViewController()
    let presenter = FoodSearchPresenter()
    
    viewController.presenter = presenter
    

    To my point about starting concrete, I mean start with FoodSearchViewController as its own thing. Don't inherit from anything except UIViewController. Then build a second view controller that would make sense in this app and would need something similar. Then extract the commonality between them. This will tend to drive you in the right direction.