У меня возникли проблемы с пониманием правильного способа создания экземпляров переменных, которые всегда нужно устанавливать до того, как объект будет полностью функциональным, но может потребоваться его создание после конструктора. Основываясь на других соглашениях и ограничениях Swift, кажется, что есть шаблон дизайна, о котором я не знаю.Инициализация свойств класса перед использованием в Swift/iOS
Вот мой случай использования:
- У меня есть класс, который наследует от UIViewController и программно создавать представления на основе действий пользователя
- мне нужно присоединить эти взгляды к этому классу, но сделать это Мне нужно получить их содержимое на основе данных конфигурации, предоставленных другим контроллером.
- Мне все равно, переданы ли эти данные конфигурации конструктору (в этом случае это всегда было необходимо) или предоставлено вторичным вызовом этому объекту до его использования
Моя проблема заключается в том, что оба подхода в пуле 3 кажутся ошибочными.
В первом случае существует только один законный конструктор, с которым может быть вызван этот класс, но я вынужден переопределить другие конструкторы и инициализировать переменные-члены с поддельными значениями, даже если другие конструкторы никогда не предназначены для использования (Я также пытаюсь сохранить эти переменные как let
типов, основанных на лучших практиках Swift).
Во втором случае я эффективно разбиваю свой конструктор на две части и вводя дополнительную точку отказа в случае, если вторая часть не будет вызвана до использования класса. Я также не могу перенести эту вторую часть на метод, который гарантированно будет вызываться до использования (например, viewDidLoad), потому что мне все равно нужно передать дополнительные аргументы из конфига. Хотя я могу убедиться, что вы вызываете initPartTwo
вручную, я бы предпочел иметь механизм, который бы лучше группировал его с фактическим конструктором. Я не могу быть первым, кто столкнулся с этим, и кажется, что есть образец, который я не вижу, чтобы сделать это чище.
UPDATE: Я в конечном итоге происходит с модифицированной версией картины матового предложил:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
Смотрите второй часть этого раздела моей книги http://www.apeth.com/swiftBook/ch03.html#_why_optionals, где я говорю о том, как «отложить инициализацию переменной». – matt
Но тогда все ссылки на эту переменную должны использовать знак вопроса. Эффективно две переменные, созданные таким же образом (но в разное время), будут доступны по-разному.Это действительно оптимальное решение? –
Нет, если они неявно развернуты. Вы все еще можете проверить «nil», если у вас есть сомнения, но вы можете ссылаться на них без знака вопроса и без восклицательного знака. – matt