Swift类不符合带有Enum的协议

时间:2018-11-08 13:48:57

标签: swift protocols

嘿,我正在尝试构建一个基类,该基类执行某些在应用程序中重复执行的操作,但是我遇到了一个我无法真正理解的问题,以下代码示例了我正在尝试的操作建立:

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] = []
}

由于Model不符合GenericModel并且ExampleVM不符合GenericVM,因此无法编译。

解决此问题的方法是使用GenericRowGenericSectionGenericModel,我的问题是为什么我不能分别使用Row,{{1} }和Section符合这些协议。

3 个答案:

答案 0 :(得分:2)

问题是,当您在协议定义中声明具体的类型要求时,就不能使用子类(如果声明的类型要求是协议类型,则不能使用符合协议的类型),而需要使用实际的(协议) ),输入符合条件的课程。

这是您看到的继承行为。您不能通过使属性的类型成为超类中声明的类型的子类来覆盖继承的属性。当使用超类类型/协议类型表示子类/符合类时,这将导致意外的行为。

您可以通过使用关联类型使协议通用来解决此问题。

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] = []
}

答案 1 :(得分:1)

您使用协议类型本身声明了GenericModel / GenericVM,而不是使用实现GenericSection / GenericRow协议的类型。

要使代码正常工作,您需要使用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] = []
}

现在它可以工作,并且了解有关您的具体类型的所有信息:

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

答案 2 :(得分:1)

根据您的协议,这将是使您创建的类和结构一致的正确方法:

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]
    }
}