2015-07-17 2 views
1

У меня возникли проблемы с пониманием правильного способа создания экземпляров переменных, которые всегда нужно устанавливать до того, как объект будет полностью функциональным, но может потребоваться его создание после конструктора. Основываясь на других соглашениях и ограничениях 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 

ответ

1

Если первоначальный экземпляр значение переменной свойства не могут быть поставлены во время инициализации объекта, обычное дело это объявить его как необязательный. Таким образом, его инициализация не должна инициализироваться инициализаторами класса (у него есть значение - это nil автоматически), плюс ваш код впоследствии может отличать неинициализированный (nil) от инициализированного (не nil).

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

Если возражение является то, что вы вынуждены открыть дверь с несколькими настройками этой переменной экземпляра, потому что теперь он должен быть объявлен с var, затем закройте дверь с сеттер наблюдателем:

struct Thing { 
    var name:String! { 
     willSet { 
      if self.name != nil { 
       fatalError("tried to set name twice") 
      } 
     } 
    } 
} 
var t = Thing() 
t.name = "Matt" // no problem 
t.name = "Rumplestiltskin" // crash 
+0

Смотрите второй часть этого раздела моей книги http://www.apeth.com/swiftBook/ch03.html#_why_optionals, где я говорю о том, как «отложить инициализацию переменной». – matt

+0

Но тогда все ссылки на эту переменную должны использовать знак вопроса. Эффективно две переменные, созданные таким же образом (но в разное время), будут доступны по-разному.Это действительно оптимальное решение? –

+0

Нет, если они неявно развернуты. Вы все еще можете проверить «nil», если у вас есть сомнения, но вы можете ссылаться на них без знака вопроса и без восклицательного знака. – matt

Смежные вопросы