Допустим, у нас есть три объекта: бабушка, родитель и ребенок. Бабушка и дедушка сохраняют родителя, родитель сохраняет ребенка, а ребенок сохраняет родителя. Бабушка и дедушка выпускают родителя.
Что произойдет в этом случае?
Допустим, у нас есть три объекта: бабушка, родитель и ребенок. Бабушка и дедушка сохраняют родителя, родитель сохраняет ребенка, а ребенок сохраняет родителя. Бабушка и дедушка выпускают родителя.
Что произойдет в этом случае?
Если нет другой ссылки на родителя или ребенка, они становятся сиротами. Но цикл сохранения между родителем и ребенком не позволяет освободиться, и они теряют память.
Ребенок никогда не должен сохранять родителя. Если что-нибудь, используйте слабую ссылку в дочернем элементе, чтобы сохранить ссылку на родителя.
Сохранение цикла - это условие. Когда 2 объекта сохраняют ссылку друг на друга и сохраняются, он создает цикл сохранения, поскольку оба объекта пытаются сохранить друг друга, что делает невозможным его освобождение.
Здесь "Дедушка" сохраняет "родителя", а "родитель" сохраняет "ребенка", где "ребенок" сохраняет "родителя". Здесь устанавливается цикл сохранения между родителем и ребенком. После освобождения бабушки и дедушки родитель и ребенок становятся сиротами, но удержание счета родителя не будет равным нулю, поскольку оно сохраняется у ребенка и, следовательно, вызывает проблему с управлением памятью.
Существует два возможных решения:
1) Используйте слабый указатель на родительский, то есть ребенок должен использовать слабую ссылку на родителя, которая не сохраняется.
2) Используйте методы "закрыть", чтобы разбить циклы удержания.
http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
В простом случае рассмотрим два объекта A и B, где A создает и сохраняет B. Когда A создается, он создает B. Когда тот, кто создал A, наконец-то выпускает его, счетчик удержания падает до нуля и освобождается. Если метод dealloc вызывает освобождение на B, показатель сохранения B также падает до нуля, и он также освобождается. [Это предполагает, что никто не сохранил A или B, потому что я делаю все просто.]
Но что произойдет, если B нуждается в ссылке обратно в A, и он сохранит A? Тот, кто создал A, может освободить его. Но так как B также сохранил A, показатель удержания не будет равен нулю. Точно так же, поскольку A сохраняет B, B сохраняет отсчет также не будет идти к нулю. Ни один из них не будет освобожден. Даже если B вызывает метод release в своем собственном dealloc, это не имеет значения, потому что этот метод никогда не будет вызван.
В этот момент у вас есть утечка памяти, потому что у вас нет ссылки на A или B, хотя они оба все еще существуют. Если A или B делает что-то более интенсивным, то вы также можете протекать процессорное время на нежелательные объекты.
В вашем случае A является родителем, а B является дочерним, а любой, кто создал A, является дедушкой.
Цикл удержания - это цикл, который происходит, когда объект А сохраняет объект B, а объект B сохраняет объект A. В этой ситуации, если один из объектов освобожден:
Таким образом, эти два объекта будут просто зависеть в памяти для жизни программы, даже если они должны, если все будет работать должным образом, освободиться.
Когда grandparent освобождает родителя, родитель все еще жив, так как ребенок сохраняет родителя.
Сохраняемый цикл - это условие, когда объекты 2 сохраняют ссылку друг на друга и сохраняются, создают цикл сохранения, поскольку оба объекта старайтесь удерживать друг друга, делая невозможным освобождение.
Пример: Человек живет в отделе, отдел имеет одного человека.
@class Department;
@interface Person:NSObject
@property (strong,nonatomic)Department * department;
@end
@implementation Person
-(void)dealloc{
NSLog(@"dealloc person");
}
@end
@interface Department: NSObject
@property (strong,nonatomic)Person * person;
@end
@implementation Department
-(void)dealloc{
NSLog(@"dealloc Department");
}
@end
Затем назовите его следующим образом:
- (void)viewDidLoad {
[super viewDidLoad];
Person * person = [[Person alloc] init];
Department * department = [[Department alloc] init];
person.department = department;
department.person = person;
}
Вы не увидите журнал dealloc, это круг сохранения.
Поскольку у объекта P сохраняется значение 1, когда оно отпущено, его keepCount переходит в 0, и его метод dealloc вызывается; Это, в свою очередь, вызывает освобождение на объекте C, счетчик которого также переходит в 0; и его метод dealloc вызывается.
Оба объекта P и C освободятся.
Когда вызывается метод dealloc объекта C, в свою очередь вызывается публикация объекта объекта GP, но поскольку GP имеет значение удержания 2, счет сохранения уменьшается до 1, и он продолжает зависать.
Дедушка: Джон Родитель: Тед Ребенок: Мэри
Вот мой пример использования телефонного звонка для иллюстрации:
Джон звонит Теду и хочет сделать телефонную конференцию с Мэри.
Тед говорит Джону: "Повесьте трубку, и я позвоню Мэри"
Тед оставляет Джона в ожидании и звонит Мэри, которая быстро отвечает на звонок.
Мэри говорит Теду: "Слей мой звонок с Джоном, и я не буду вешать трубку, пока я не закончу"
Тед, не получив ответа от Джона некоторое время, оставляет призыв сделать что-то еще.
Джон идет, чтобы объединить звонки с Тедом и Мэри, а затем внезапно умирает.
Мэри застряла на линии с Джоном, но никогда не повесит трубку, потому что Джон не вернется!