Подтвердить что ты не робот

Вызов методов из инициализатора Swift

Скажем, у меня есть следующий класс в Swift (который имеет очевидные проблемы)

class MyClass {
    let myProperty: String

    init() {
        super.init()
        self.setupMyProperty()
    }

    func setupMyProperty() {
        myProperty = "x"
    }
}

Это слишком упрощено, но я в основном пытаюсь делегировать инициализацию myProperty в метод setupMyProperty(). Это шаблон, который я часто использую для разбивки различных частей установки класса.

Но, конечно, я не могу вызвать self до запуска супер инициализатора, и я не могу запустить супер инициализатор до тех пор, пока все свойства не будут установлены, поэтому я попал в ловушку 22. Наверх из него, поскольку setupMyProperty() не считается инициализатором, он все равно не сможет назначить myProperty.

Может ли кто-нибудь сказать мне, как реализовать этот шаблон в Swift?

4b9b3361

Ответ 1

объявить его как неявно развернутый необязательный

class MyClass : NSObject {
    var myProperty: String!

    init() {
        super.init()
        self.setupMyProperty()
    }

    func setupMyProperty() {
        self.myProperty = "x"
    }
}

стр. 499 руководства "Язык быстрого программирования"

Ответ 2

Нужно ли setupMyProperty получить доступ к себе? Если нет, вы можете добиться этого с помощью метода класса:

class MyClass: NSObject {
    let myProperty: String

    init() {
        myProperty = MyClass.setupMyProperty()
        super.init()
    }

    class func setupMyProperty() -> String {
        return "foo"
    }
}

Ответ 3

Вы не можете использовать self, пока ваша память экземпляра не будет полностью инициализирована (после чего вы не сможете больше устанавливать постоянные свойства), поэтому порядок, в котором должен выполняться ваш назначенный инициализатор:

  • инициализировать все свойства, добавленные этим классом
  • инициализатор суперкласса вызова (если есть суперкласс)
  • теперь вы можете использовать self, методы вызова и т.д.

Я не уверен, есть ли подходящее обходное решение для случая свойства константы. Одним из альтернатив было бы объявить свойство как неявно развернутое необязательное, поэтому оно первоначально установлено на nil:

class MyClass {
    var myProperty: String!
    init() {
        super.init() // only if you actually have a superclass, and make sure this does not use `myProperty`
        self.setupMyProperty()
    }

    func setupMyProperty() {
        myProperty = "x"
    }
}

Будьте осторожны с этим, он теряет немного безопасности типа, так как myProperty теперь может быть nil, и если вы пытаетесь получить к нему доступ, это приведет к ошибке выполнения. Поэтому сделайте это только в том случае, если вы уверены, что он будет инициализирован всеми вашими инициализаторами, которые не будут использоваться ничем, вызываемым до setupMyProperty() в цепочке инициализатора (например, когда инициализатор суперкласса вызывает метод, который вы переопределяете, обращаясь к myProperty) и никогда не устанавливают значение nil явно.

Кроме того, ср. документы, особенно раздел о наследовании и инициализации класса для всего материала для заказа, описанного выше.

Ответ 4

Попробуйте установить setupMyProperty() в константу. Затем он находится перед инициализацией, и вы можете вызвать его из init(). Вы можете даже получить доступ к следующим параметрам:

class MyClass {
    var myProperty: String
    let setupMyProperty : (String) -> (void) = { 
        param in
        self.myProperty = param
    }

    init(x: String) {
    // removed redundant line: super.init()
        self.setupMyProperty(x)
    }
}