Извлечь код инициализации для константного свойства класса Swift - PullRequest
0 голосов
/ 20 февраля 2019
class Foo {
    let result: CGFloat

    init() {
        result = calculate()
    }

    private func calculate() -> CGFloat {
        // do many complex calculation with many codes
        return 0
    }
}

Нет сомнений, что ошибка возникает.

«self», используемое в вызове метода «Calculate» до инициализации всех сохраненных свойств`

Я знаю несколько способов решения этой проблемы.

  1. var вместо let.например, var result
  2. lazy.например, lazy result: CGFloat = { return 0 }
  3. сделать calculate() равным class/static или глобальной функции.например, static func calculate().

Но я думаю, что это не то, что я хочу.

Почему let

let означает неизменность.Хотя расчет result может быть сложным, но он действительно неизменен.Так что var не лучшая практика.

Почему calculate()

Слишком много кодов в init() не идиоматично и не раздражает

Почему бы не class/static

Другие свойства экземпляра нельзя использовать в статической функции.


Обновление

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = calculate()
    }

    private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

Для большей ясности я добавлю еще один фрагмент.На самом деле result то же самое с foo3.Так почему foo3 = foo1 * foo2, а result = calculate()?

Это потому, что вычисление result (возможно, 10 строк кода) немного сложнее, чем вычисление foo3 (только одна строка).Если я введу все эти коды в init(), это будет грязно.


Попробуйте все упомянутые способы

1.var вместо let

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    var result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = calculate()
    }

    private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

Работает, но result не является неизменным.

2.lazy

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    lazy var result: CGFloat = {
        calculate()
    }()

    init() {
        foo3 = foo1 * foo2
    }

    private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

Работает, но result также не является неизменным.

3.статическая функция

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = Foo.calculate()
    }

    static private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

Сборка не удалась,

Элемент экземпляра 'foo3' нельзя использовать для типа 'Foo'

4.закрытие

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat
    private let calculate = { () -> CGFloat in
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }

    init() {
        foo3 = foo1 * foo2
        result = calculate()
    }
}

Сборка не удалась,

Элемент экземпляра 'foo3' нельзя использовать для типа 'Foo'

5.вычислительное свойство

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    var result: CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }

    init() {
        foo3 = foo1 * foo2
    }
}

Работает, но результатом является 'var' и будет рассчитываться для каждого использования.

6.класс инструмента

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = Tool.calculate(foo3: foo3)
    }
}

class Tool {
    static func calculate(foo3: CGFloat) -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

Работает, но мы вводим Tool класс.

Резюме

1, 2, 6 подходит.6 подходит для сложных вычислений.

Расширение

"Неявно развернутые необязательные параметры" упоминается несколько раз.Я запутался, почему пока не вижу этот ответ .

1 Ответ

0 голосов
/ 20 февраля 2019

Два других способа, о которых вы не упомянули, превращают result в один из

  • неявно развернутого необязательного
  • вычисляемого свойства

В-третьих, переместите вычисление в его собственный тип / свободную функцию и предоставьте его этому классу.Вероятно, это правильное решение.

Swift просто не позволит вам делать то, что вы пытаетесь сделать: правило состоит в том, что все сохраненные свойства должны быть установлены до того, как вы что-то сделаете с другими свойствами нового экземпляра.,Он твердо придерживается мнения, что все, что не может быть правильным, должно быть запрещено.

Например, что если вы изменили calculate для чтения из result?Или что, если подкласс сделал это?Вы можете столкнуться с ситуацией, когда значение не просто неопределено, а неопределимо.

...