Swift: шаблон Init () для отношений между родителями и детьми - PullRequest
1 голос
/ 02 марта 2020

Настройка

Предположим, у меня есть два класса:

final class Parent: NSObject 
{
   var child: Child
}


final class Child: NSObject 
{
   weak var parent: Parent?

   init(parent: Parent) 
   {
      self.parent = parent
   }
}

Вопрос:

Теперь предположим, что я хочу создать экземпляр child и установить sh это соотношение в init() методе Parent. Я бы сделал это:

final class Parent: NSObject 
{
   var child: Child

   init() 
   {
      child = Child.init(parent: self)    // ERROR!
   }
} 

Свифт, который я использую self до super.init(). Если я ставлю super.init() до того, как создаю экземпляр child, Свифт скулит, что child не присвоено значение при вызове super.init().

Я закрывал Swift, используя неявно развернутые опции, например:

final class Parent: NSObject 
{
   var child: Child!

   init() 
   {
      super.init()
      child.init(parent: self)
   }
}

Мой вопрос: что люди делают в этой ситуации? Это / был ОЧЕНЬ распространенный паттерн в Objective- C, и Swift не производит ничего, кроме головной боли. Я понимаю, что могу отменить присвоение parent от Child s init(), чтобы я мог init() child, позвонить super.init(), а затем назначить parent, но это не вариант в реальных случаях, когда я сталкиваюсь с этим. Это также уродливо и раздуто.

Я понимаю, что цель Свифта - предотвратить использование объекта до его полной инициализации. И что для child init() возможно перезвонить на parent и состояние доступа, которое еще не настроено, что становится опасностью при неявно развернутом необязательном подходе.

I Здесь я не могу найти никаких советов о наилучшей практике Swift, поэтому я спрашиваю, как люди решают эту проблему с яйцом и курицей. Действительно ли превращение свойств в неявно развернутые необязательные параметры - лучший способ обойти это ограничение? Спасибо.

1 Ответ

0 голосов
/ 02 марта 2020

Вы можете сделать это lazy, и все ваши головные боли исчезнут!

final class Parent {
    lazy var child = Child(parent: self)
}


final class Child {
    weak var parent: Parent?

    init(parent: Parent) {
        self.parent = parent
    }
}

В Swift все сохраненные свойства должны быть инициализированы до того, как станет доступным self. Включая сохраненные свойства в superclass. Так что Xcode не позволяет вам использовать self до тех пор. Но использование lazy означает, что инициализируется ранее. Таким образом, вы можете свободно использовать self.

Некоторые полезные замечания:

  1. Не наследуйте от NSObject, если вам не нужны objc расширенные функции для вашего класса .
  2. В соглашении о быстром именовании открытые скобки ( будут читать как with в target- C. Таким образом, вам не нужно withParent в качестве метки в инициализаторе.
  3. Используйте внутренние и внешние имена аргументов в соответствии с соглашением.

Также обратите внимание, что некоторые вышеупомянутые примечания написаны перед комментариями

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...