Класс Swift не соответствует протоколу с Enum - PullRequest
0 голосов
/ 08 ноября 2018

Хи, я пытаюсь создать базовый класс, который выполняет определенные действия, повторяющиеся в приложении, но я столкнулся с проблемой, которую не могу понять, следующий код иллюстрирует то, что я пытаюсь построить:

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.

Способ решения этой проблемы - использование GenericRow, GenericSection и GenericModel. Мой вопрос: почему я не могу использовать соответствующие Row, Section и Model, соответствующие этим протоколам? .

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Исходя из ваших протоколов, это будет правильный способ привести классы и структуры, которые вы создали, в соответствие:

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]
    }
}
0 голосов
/ 08 ноября 2018

Проблема в том, что когда вы объявляете конкретное требование типа в определении протокола, вы не можете использовать подкласс (или тип, соответствующий протоколу, если объявленное требование типа является типом протокола), вам нужно использовать фактическое (протокол ) введите соответствующий класс.

Это поведение, которое вы видите для наследования. Вы не можете переопределить унаследованное свойство, сделав тип свойства подклассом типа, объявленного в суперклассе. Это может привести к неожиданному поведению при использовании типа суперкласса / типа протокола для представления подклассов / соответствующих классов.

Вы можете обойти эту проблему, сделав свой протокол универсальным, используя связанные типы.

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] = []
}
0 голосов
/ 08 ноября 2018

Вы объявили 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])]
...