简体   繁体   中英

Swift class does not conform to Protocol with Enum

Hy, I'm trying to build a base class that does certain actions that repeat themselves along the app, but I'm faced with an issue that I can't really comprehend, the following code exemplifies what I'm trying to build:

protocol GenericSection { }
protocol GenericRow { }

protocol GenericModel {
    var section: GenericSection { get }
    var items: [GenericRow] { get }
}

protocol GenericVM {
    var model: [GenericModel] { get set }
}

class ExampleVM: GenericVM {

    enum Row: GenericRow {
        case aRow
    }

    enum Section: GenericSection {
        case aSection
    }

    struct Model: GenericModel {
        let section: Section
        let items: [Row]
    }

    var model: [Model] = []
}

This does not compile because Model does not conform to GenericModel and ExampleVM does not conform to GenericVM .

The way it solves this is by using GenericRow , GenericSection and GenericModel , my question is why can't I use the respective Row , Section and Model that conform to those protocols.

The issue is that when you declare a concrete type requirement in a protocol definition, you cannot use a subclass (or type conforming to the protocol if the declared type requirement is a protocol type), you need to use the actual (protocol) type in the conforming class.

This is the behaviour you see for inheritance. You cannot override an inherited property by making the type of the property a subclass of the type declared in the superclass. This would result in unexpected behaviour when using the superclass type/protocol type to represent subclasses/conforming classes.

You can get around this issue by making your protocol generic using associated types.

protocol GenericSection { }
protocol GenericRow { }

protocol GenericModel {
    associatedtype Section:GenericSection
    associatedtype Row: GenericRow

    var section: Section { get }
    var items: [Row] { get }
}

protocol GenericVM {
    associatedtype Model: GenericModel
    var model: [Model] { get set }
}

class ExampleVM: GenericVM {

    enum Row: GenericRow {
        case aRow
    }

    enum Section: GenericSection {
        case aSection
    }

    struct Model: GenericModel {
        let section: Section
        let items: [Row]
    }

    var model: [Model] = []
}

You declared your GenericModel / GenericVM using protocol types per se, not types implementing your GenericSection / GenericRow protocols.

To make your code work you gonna need to use associatedtype s:

protocol GenericSection { }
protocol GenericRow { }

protocol GenericModel {
    associatedtype SectionType: GenericSection
    associatedtype RowType: GenericRow

    var section: SectionType { get }
    var items: [RowType] { get }
}

protocol GenericVM {
    associatedtype ModelType: GenericModel

    var model: [ModelType] { get set }
}

class ExampleVM: GenericVM {

    enum Row: GenericRow {
        case aRow
    }

    enum Section: GenericSection {
        case aSection
    }

    struct Model: GenericModel {
        let section: Section
        let items: [Row]
    }

    var model: [Model] = []
}

And now it works, and knows everything about your concrete types:

let vm = ExampleVM()
vm.model = [.init(section: .aSection, items: [.aRow])]

Based on your protocols, this would be the correct way to make the classes and structs you created conform:

protocol GenericSection { }
protocol GenericRow { }

protocol GenericModel {
    var section: GenericSection { get }
    var items: [GenericRow] { get }
}

protocol GenericVM {
    var model: [GenericModel] { get set }
}

class ExampleVM: GenericVM {

    var model: [GenericModel] = []

    enum Row: GenericRow {
        case aRow
    }

    enum Section: GenericSection {
        case aSection
    }

    struct Model: GenericModel {
        var section: GenericSection
        var items: [GenericRow]
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM