Andrey Gordeev
Andrey Gordeev

Reputation: 32559

Multiple generic class inheritance in Swift

Consider I have one model and a base model for it:

class BaseModel: NSObject {
    var name = ""
}

class Model: BaseModel {
    var desc = "abc"
}

I added a services to work with those models:

class AbstractService<T: NSObject>: NSObject {
    var items = [T]()
}

class BaseModelService<T: BaseModel>: AbstractService<BaseModel> {
}

class ModelService<T: Model>: BaseModelService<Model> {
}

Now I want to access items variable from ModelService and expect to get an array of Models, but I get BaseModels instead:

Error message: Cannot assign a value of type [BaseModel] to a value of type [Model]

Did I miss something with generics?

Here is a full code for Playground:

//: Playground - noun: a place where people can play

import UIKit

/// Models:
class BaseModel: NSObject {
    var name = ""
}

class Model: BaseModel {
    var desc = "abc"
}

/// Services:
class AbstractService<T: NSObject>: NSObject {
    var items = [T]()
}

class BaseModelService<T: BaseModel>: AbstractService<BaseModel> {
}

class ModelService<T: Model>: BaseModelService<Model> {
}

/// ViewController:
class ViewController: UIViewController {

    let modelService = ModelService()
    var items = [Model]()

    override func viewDidLoad() {
        super.viewDidLoad()

        items = modelService.items // The error appears here: Cannot assign a value of type [BaseModel] to a value of type [Model]
    }

}

Upvotes: 0

Views: 404

Answers (2)

rintaro
rintaro

Reputation: 51911

In your case, the declarations should be:

class BaseModelService<T: BaseModel>: AbstractService<T> {
}

class ModelService: BaseModelService<Model> {
}

When you do:

class BaseModelService<T: BaseModel>: AbstractService<BaseModel> {
}

T for AbstractService and T for BaseModelService are two distinct types. The former constrained to concrete BaseModel, whereas the latter is constrained to subtype of BaseModel, and not used at all.

Upvotes: 1

JeremyP
JeremyP

Reputation: 86691

The problem is that you force BaseModelService to be a subclass of AbstractModelService<BaseModel> which means that items is typed [BaseModel]. Declare BaseModelService as follows:

class BaseModelService<T: BaseModel>: AbstractService<T> {

Then you are good to go.

Upvotes: 2

Related Questions