Свифт сохранил цикл пропущенного разъяснения - PullRequest
0 голосов
/ 04 мая 2019

Apple имеет документацию, которая описывает, как циклы сохранения работают в замыканиях . Это их пример закрытия, которое не вызывает цикл сохранения.

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

Иногда мне хочется передать определение функции в обратный вызов, чтобы попытаться избавить мой код от ада обратного вызова.

Этот пример немного надуманный, но вызывает ли это цикл сохранения? Присвоит ли функция, подобная этой, замыканию, цикл сохранения?

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = self.returnHTML

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    func returnHTML() -> String {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

1 Ответ

2 голосов
/ 04 мая 2019

Ваш пример на самом деле недостаточно надуманен. Давайте сделаем это проще:

class C {
    lazy var f: () -> () = {
        [unowned self] in
        print(self)
    }
    init() {}
    func doF() {
        self.f()
    }
    deinit {
        print("C is being deinitialized")
    }
}

Теперь давайте проверим это:

    let c = C()
    c.doF()

Результат: когда c выходит из области видимости, мы видим "C деинициализируется".

Хорошо, но теперь удалите [unowned self] in. Теперь, когда мы проверяем это, мы не видим "C деинициализируется". У нас есть цикл сохранения.

Так что да, у вас есть self, сохраняющая функцию, которая ссылается на self, это цикл сохранения. Вы правы, чтобы разорвать цикл с unowned self.

(Конечно, в моем примере я учитываю, как ваш lazy усложняет картину. Если мы не скажем self.f() - то есть, если мы никогда не попросим lazy var инициализировать сам по себе - тогда, конечно, не имеет значения что такое инициализатор для f: он никогда не инициализируется, поэтому не может быть никакого цикла сохранения. Но это крайне невероятный сценарий, если вы никогда не собираетесь для инициализации lazy var тогда у вас не будет lazy var для начала.)

...