Как возможен сильный цикл удержания с асинхронными или статическими вызовами?
Я пытаюсь понять, как я могу распознать, когда возможен сильный цикл удержания, который требует от меня использования [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://digitalleaves.com/blog/2015/05/demystifying-retain-cycles-in-arc/