Swift: ссылка на себя во вложенных замыканиях

Я использую новый блочный KVO API в Swift для наблюдения за свойствами. Ниже приведен пример кода.

class A: NSObject {
var observerA: NSKeyValueObservation? = nil
var observerB: NSKeyValueObservation? = nil

var property1: CustomObj1?
var property2: CustomObj2?

func doSomething() {

}

func doSomethingElse() {

}

func observeValues() {
    observerA = customObj1.observe(\.property1, options: [], changeHandler: { [weak self] (obj, change) in
        guard let strongSelf = self else { return }
        strongSelf.doSomething()
        strongSelf.observerB = customObj2.observe(\.property2, options: [], changeHandler: { [weak strongSelf] (nestedObj, nestedChange) in
            guard let nestedStrongSelf = strongSelf else { return }
            nestedStrongSelf.doSomethingElse()
        })
    })
}

}

Мой вопрос в том, как мы ссылаемся на self во внутреннем блоке обработчика изменений. Я мог бы использовать его, как указано выше, и я не вижу утечек памяти. Но использование self вместо strongSelf в «[weak strongSelf]» внутри внутреннего обработчика изменений также не вызывает никаких проблем. Вот код.

func observeValues() {
observerA = self.observe(\.property1, options: [], changeHandler: { [weak self] (obj, change) in
    guard let strongSelf = self else { return }
    strongSelf.doSomething()
    strongSelf.observerB = strongSelf.observe(\.property2, options: [], changeHandler: { [weak self] (nestedObj, nestedChange) in
        guard let nestedStrongSelf = self else { return }
        nestedStrongSelf.doSomethingElse()
    })
})

}

Мой вопрос заключается в том, как следует ссылаться на self во вложенных обработчиках завершения и что в этом должно быть наилучшей практикой. Спасибо.


person Swift Technocrat    schedule 22.10.2018    source источник
comment
Прошу прощения за свой неправильный ответ ранее! Оказывается, вы абсолютно правы. Я всегда использую [unowned self], чтобы справиться с этой ситуацией.   -  person matt    schedule 22.10.2018
comment
Почему бы вам не использовать [weak self], поскольку вы обнаружили, что это не вызывает проблем?   -  person OOPer    schedule 23.10.2018
comment
Ага, это можно сделать. Но я просто использовал strongSelf для лучшей читабельности.   -  person Swift Technocrat    schedule 23.10.2018


Ответы (1)


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

Например, если этот VC активен на протяжении всего жизненного цикла приложения, даже если замыкание фиксирует сильный эталонный цикл, оно ничего не сделает. Последствия будут такими же: венчурный капитал будет существовать в течение всего срока службы приложения, что он и так уже делал.

Вы сможете определить утечку памяти только в том случае, если у вас есть сильный цикл ссылок, а затем вы попытаетесь деинициализировать VC, удалив все другие сильные ссылки.

person Alexander    schedule 22.10.2018
comment
VC не будет работать в течение всего времени существования приложения, и я бы хотел, чтобы VC и контроллер его модели были освобождены после закрытия экрана, который представляет VC. У меня нет проблем с сохранением кода выше. Я ищу лучший способ получить доступ к себе во вложенном обработчике изменений. Должен ли я просто называть себя «я» во вложенном блоке или я должен ссылаться на более слабую версию self (strongSelf), объявленную в списке захвата родительского блока. - person Swift Technocrat; 22.10.2018
comment
@SwiftTechnocrat Итак, когда вы закроете экран этого VC, вы должны увидеть утечку памяти в Instruments. - person Alexander; 22.10.2018
comment
Да, я вижу утечку памяти, и deinit никогда не выполняется, когда я не объявляю себя слабым в родительском блоке. - person Swift Technocrat; 23.10.2018
comment
@SwiftTechnocrat Да, это имеет смысл. Тогда я не думаю, что понимаю ваш вопрос, о чем вы спрашиваете? В гнездовом прицеле надо self слабо захватывать, точно так же. - person Alexander; 23.10.2018
comment
Да, я должен быть захвачен слабо. Не имеет значения, упоминается ли он как self или как слабая версия self, т.е. strongSelf в данном случае. Технически оба одинаковы. У меня сложилось впечатление, что использование self во вложенном блоке для списка захвата может вызвать циклы сохранения. Спасибо за ваш вклад. - person Swift Technocrat; 23.10.2018