Допустим, у меня есть следующий протокол:
protocol Identifiable {
var id: Int {get}
var name: String {get}
}
И что у меня есть следующие структуры:
struct A: Identifiable {
var id: Int
var name: String
}
struct B: Identifiable {
var id: Int
var name: String
}
Как видите, я должен был "соответствовать" протоколу идентификации в структурах A и B. Но представьте, если бы у меня было N дополнительных структур, которые должны соответствовать этому протоколу... Я не хочу " скопировать/вставить соответствие (идентификатор переменной: Int, имя переменной: строка)
Поэтому я создаю расширение протокола:
extension Identifiable {
var id: Int {
return 0
}
var name: String {
return "default"
}
}
С помощью этого расширения теперь я могу создать структуру, соответствующую протоколу идентификации, без необходимости реализации обоих свойств:
struct C: Identifiable {
}
Теперь проблема в том, что я не могу установить значение свойства id или свойства name:
var c: C = C()
c.id = 12 // Cannot assign to property: 'id' is a get-only property
Это происходит из-за того, что в протоколе идентификации идентификатор и имя доступны только для получения. Теперь, если я изменю свойства id и name на {get set}, я получу следующую ошибку:
Тип 'C' не соответствует протоколу 'Идентифицируемый'
Эта ошибка возникает из-за того, что я не реализовал сеттер в расширении протокола... Поэтому я меняю расширение протокола:
extension Identifiable {
var id: Int {
get {
return 0
}
set {
}
}
var name: String {
get {
return "default"
}
set {
}
}
}
Теперь ошибка исчезает, но если я устанавливаю новое значение id или name, оно получает значение по умолчанию (геттер). Конечно, сеттер пуст.
Мой вопрос: Какой фрагмент кода мне нужно поместить в сеттер? Потому что, если я добавлю self.id = newValue, произойдет сбой (рекурсивный).
Заранее спасибо.
Привет! Спасибо за Ваш ответ. Мне очень нравится эта компонентная техника. С этого момента я пытаюсь принять протокольно-ориентированное программирование, поэтому я искал что-то подобное.
@Axort: пожалуйста. Я также предлагаю вам посмотреть это видео о протокольно-ориентированном программировании с WWDC 2015 года. Очень интересно.
Почему у вас есть протокол HasIdentifiedComponent? Почему бы просто не сделать
protocol Identifiable: var identifiableComponent: IdentifiableComponent { get set }
Затемextension Identifiable { var id: Int { get { return identifiableComponent.id } set { identifiableComponent.id = newValue } } etc... }
Не могли бы вы объяснить, почему вы создаете 2 протокола (HasIdentifiableComponent и Identifying) в примере с компонентами?
@BohdanSavych Просто потому, что я хотел отделить понятие
HasIdentifiableComponent
от понятияIdentifiable
. Если вам не нравится такое разделение, не стесняйтесь группировать все в один протокол.Я получаю сообщение об ошибке «Невозможно присвоить свойству: вызов функции возвращает неизменное значение» в Swift 4 при попытке установить любое свойство. Аналогичная ошибка при попытке установить эти свойства из соответствующего класса, говоря, что self неизменяемо. Должны ли они быть протоколами только для класса?
Если вы готовы задействовать среду выполнения Objective C, вы также можете воспользоваться Associated Objects в качестве резервного хранилища для свойств расширения. См. nshipster.com/swift-objc-runtime и marcosantadev.com/stored-properties-swift-extensions для примеров и обсуждения.
@LucaAngeletti, как бы вы справились с этим, когда протокол определяет ассоциированный тип, а также имеет сохраненное свойство этого типа.