Как возможен сильный цикл удержания с асинхронными или статическими вызовами?

Я пытаюсь понять, как я могу распознать, когда возможен сильный цикл удержания, который требует от меня использования [weak/unowned self], Я был сожжен ненужным использованием [weak/unowned self] и я был освобожден непосредственно перед тем, как дать мне возможность его использовать.

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

NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
  (data, response, error) in
  self.data = data
)

Вот еще один пример использования NSNotificationCenter, где вызов может быть сделан позже асинхронно:

 NSNotificationCenter.defaultCenter().addObserverForName(
        UIApplicationSignificantTimeChangeNotification, object: nil, queue: nil) {
            [unowned self] _ in
            self.refresh()
    }

Мой вопрос: в каких случаях возможен сильный цикл удержания? Если я делаю асинхронный или статический вызов, который ссылается на себя в замыкании, делает ли это его кандидатом на [weak/unowned self]? Спасибо, что пролил свет на это.

2 ответа

В двух словах:

Цикл сохранения может произойти в двух случаях.

Случай 1:

Когда два экземпляра держат сильную ссылку друг на друга. Вы должны решить это, пометив одного из них как слабого.

Случай 2: (который связан с вашими вопросами)

Если вы назначаете замыкание свойству экземпляра класса, и тело этого замыкания захватывает экземпляр.

В ваших двух примерах нет необходимости использовать слабое Я вообще как NSNotificationCenter ни NSURLSession являются свойствами для вашего экземпляра класса. (Или в другом смысле, у вас нет сильных ссылок на них)

Проверьте этот пример, где я должен использовать слабое Я:

[self.mm_drawerController setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {

    if (drawerSide == MMDrawerSideRight && percentVisible == 1.0) {
        [weakself showOverlayBgWithCloseButton:YES];
    }
    else{

        [weakself hideOverlayBg];
    }
}];

У меня есть сильная ссылка на mm_drawerController и я назначаю закрытие на это правильно? внутри этого замысла я хочу захватить себя. Таким образом, закрытие будет иметь сильную ссылку на себя! Это катастрофа. В этом случае у вас будет цикл сохранения. Чтобы разорвать этот цикл, используйте слабое Я внутри замыкания.

Цикл сохранения - это ситуация, когда два объекта тесно связаны друг с другом.

Вы работаете со статическими переменными NSURLSession.sharedSession() и NSNotificationCenter.defaultCenter() и, как вы помните:

Одноэлементный объект обеспечивает глобальную точку доступа к ресурсам своего класса... Вы получаете глобальный экземпляр из одноэлементного класса через фабричный метод. Класс лениво создает свой единственный экземпляр при первом запросе и после этого гарантирует, что никакой другой экземпляр не может быть создан. Класс Singleton также запрещает вызывающим сторонам копировать, сохранять или освобождать экземпляр.

https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Singleton.html

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

Проверьте эту замечательную статью для более подробной информации: https://digitalleaves.com/blog/2015/05/demystifying-retain-cycles-in-arc/

Другие вопросы по тегам