Должен ли я ослабить «локальные» переменные, используемые в блоке? - PullRequest
0 голосов
/ 27 апреля 2018

Это не другой вопрос о [weak self]. Речь идет об использовании переменных, не содержащихся в self, а в функции обтекания.

func someFunction(){
    someOtherFunction(completionBlock:{ [weak self] in
        self?.doStuff()
    })
}

Насколько я понимаю, мне нужен [weak self], чтобы предотвратить цикл сохранения.

Но что, если мне нужно использовать переменную из функции обтекания, например:

func someFunction(){
    let someVariable = MyObject()
    someOtherFunction(completionBlock:{ [weak self] in
        self?.doStuff(with: someVariable)
    })
}

Это работает, и это заставляет меня задуматься. Как и как долго someVariable хранится в памяти? Может ли он создать свой собственный крошечный цикл сохранения, где мой блок завершения строго ссылается на локальный someVariable? Как они будут выпущены? Должен ли добавить [weak self, weak someVariable] в блок? Но тогда, someVariable не будет выпущен сразу после того, как я вызову someOtherFunction, потому что это конец этой функции - и конец жизни someVariable ..?

У меня проблемы с полным пониманием ссылок, и я не вижу, как мои completionBlock и someVariable когда-либо будут выпущены. Блоки вообще освобождены?

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

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

Давайте рассмотрим эту ситуацию:

func someFunction() {
    let object = Something()
    object.handler = { [weak self] in 
       self?.doStuff(with: object)
    }
}

Теперь есть цикл сохранения, и object нельзя отменить, пока кто-нибудь не сбросит handler вручную. Потому что теперь объект укрепляется в захваченном блоке.

Итак, лучшее решение:

func someFunction() {
    let object = Something()
    object.handler = { [weak self, unowned object] in 
       self?.doStuff(with: object)
    }
}

И хорошей практикой является передача object в качестве аргумента в handler

func someFunction() {
    let object = Something()
    object.handler = { [weak self] (object) in 
       self?.doStuff(with: object)
    }
}

Так что подпись должна выглядеть так:

class Something {
    var handler:((Something) -> Void)?
    deinit {
        print("retain cycle is not here")
    }
}
0 голосов
/ 27 апреля 2018

Любая переменная, на которую есть ссылка в закрытии, будет сильно сохраняться этим закрытием. Вы можете настроить это, включив список захвата закрытия (например, [weak self]), который позволяет вам указать конкретный шаблон управления памятью ссылок, захваченных в закрытии.

func someFunction(){
    let someVariable = MyObject()
    someOtherFunction(completionBlock:{ [weak self] in
        self?.doStuff(with: someVariable)
    })
}

Здесь, someVariable удерживается закрытием, как вы заявили. В этом случае он должен иметь , потому что это больше никому не нужно. Как вы упомянули в комментариях, если вы использовали список захвата [weak someVariable], то при выполнении блока завершения он всегда будет равен нулю, так как он вышел из области видимости в своей исходной функции.

«Крошечный цикл сохранения» не создается. Цикл сохранения должен быть цикл - то есть A содержит сильную ссылку на B, которая содержит сильную ссылку на A. someVariable не имеет ссылок ни на что.

Как только someOtherFunction закончится со ссылкой на завершение завершения, все исчезнет. Закрытие - это еще одна переменная, что касается someOtherFunction, и оно будет существовать до тех пор, пока оно находится в области видимости.

Должен ли я ослабить «локальные» переменные, используемые в блоке? - нет, поскольку к тому времени, когда блок их использует, они будут равны нулю.

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