Использование подкласса требования протокола - PullRequest
2 голосов
/ 10 октября 2019

Я работаю над проектом, использующим MVVM, и мы хотели бы повысить безопасность, не позволяя вызывающей стороне изменять объекты, которые мы выставляем.

Мы не можем сделать Immutable a struct и просто пометьте mutate() как mutating, потому что мы добавляем наблюдателей, которые мутируют нужный нам объект в форме Immutable.

В этом примере показано, что мы хотели быда, но мы просто получаем ошибку, которую C не подтверждает P, потому что мы пытаемся удовлетворить протокол подклассом необходимого Immutable, Mutable

class Immutable {}

class Mutable: Immutable {
    func mutate() {}
}
​
protocol P {
    var a: Immutable { get }
}
​
class C: P {
    let a: Mutable
​
    init() {
        a = Mutable()
        a.mutate()
    }
}

Есть ли у кого-нибудь креативное решение для этого, которое не требует большого количества шаблонов для обхода, например, создание Immutable для удовлетворения требований к типу и последующее приведение в линию, например:

class C: P {
    let a: Immutable
​
    init() {
        a = Mutable()
        (a as? Mutable)?.mutate()
    }
}

Это неэто не идеально для нас, потому что мы звоним mutate() много, много раз и не хотим рефакторинга всего нашего кода.

1 Ответ

0 голосов
/ 10 октября 2019

Измените protocol P на associatedtype, как показано ниже,

protocol P {
    associatedtype T: Immutable
    var a: T { get set }
}

Поскольку вы присваивали значение переменной a внутри class, которая соответствует Pпоэтому объявление переменной a изменилось, как указано выше, чтобы разрешить установку значения.

Теперь вы можете определить тип внутри соответствующего class как,

class C: P  {
    var a: Mutable

    init() {
        self.a = Mutable()
        self.a.mutate()
    }
}
...