Допустим, у нас есть три объекта: бабушка и дедушка, родитель и ребенок. Прадедушка оставляет за собой родителя, родитель сохраняет ребенка, а ребенок сохраняет родителя. Бабушка и дедушка отпускают родителя.
Что будет в этом случае?
Допустим, у нас есть три объекта: бабушка и дедушка, родитель и ребенок. Прадедушка оставляет за собой родителя, родитель сохраняет ребенка, а ребенок сохраняет родителя. Бабушка и дедушка отпускают родителя.
Что будет в этом случае?
Если нет другой ссылки на родителя или ребенка, они оба становятся сиротами. Но цикл сохранения между родителем и потомком предотвращает освобождение любого из них, и они становятся потраченной впустую памятью.
Ребенок никогда не должен оставлять себе родителей. Во всяком случае, используйте слабую ссылку в дочернем элементе, чтобы поддерживать ссылку на родителя.
Цикл сохранения - это условие. Когда 2 объекта сохраняют ссылку друг на друга и сохраняются, он создает цикл сохранения, поскольку оба объекта пытаются сохранить друг друга, что делает невозможным освобождение.
Здесь «бабушка и дедушка» сохраняет «родителя», а «родитель» сохраняет «дочерний элемент», тогда как «дочерний элемент» сохраняет «родителя». Здесь устанавливается цикл сохранения между родителем и дочерним элементом. После освобождения бабушки и дедушки и родитель, и потомок становятся сиротами, но счетчик удержания родителя не будет равен нулю, так как он сохраняется дочерним и, следовательно, вызывает проблему с управлением памятью.
Есть два возможных решения:
1) Используйте слабый указатель на родителя, т.е. дочерний элемент должен использовать слабую ссылку на родителя, которая не сохраняется.
2) Используйте методы «закрытия», чтобы разорвать циклы сохранения.
http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
В простом случае рассмотрим два объекта A и B, где A создает и сохраняет B. Когда A создается, он создает B. Когда тот, кто создал A, наконец, освобождает его, счетчик сохранения A падает до нуля, и он освобождается. Если метод dealloc A вызывает release для B, счетчик сохранения B также падает до нуля, и он также освобождается. [Это предполагает, что никто другой не сохранил A или B, потому что я упрощаю.]
Но что произойдет, если B потребуется обратная ссылка на A, и он сохранит A? Кто бы ни создал A, может выпустить его. Но поскольку B также сохранил A, счетчик удержания A не станет равным нулю. Точно так же, поскольку A сохраняет B, счетчик удержания B также не обнуляется. Ни то, ни другое не будет освобождено. Даже если B вызывает метод выпуска A в своем собственном освобождении, это не имеет значения, потому что этот метод никогда не будет вызван.
На этом этапе у вас есть утечка памяти, потому что у вас нет ссылки на A или B, хотя они оба все еще существуют. Если A или B что-то интенсивно используют для процессора, вы также можете терять процессорное время для нежелательных объектов.
В вашем случае A - родитель, а B - ребенок, и тот, кто создал A, является дедушкой или бабушкой.
Цикл сохранения - это цикл, который происходит, когда объект A сохраняет объект B, а объект B сохраняет объект A. В этой ситуации, если один из объектов освобожден:
Таким образом, эти два объекта просто будут оставаться в памяти на протяжении всей жизни программы, даже если они должны быть освобождены, если все работает правильно.
Когда дедушка и бабушка освобождают родителя, родитель все еще жив, поскольку ребенок сохраняет родителя.
Дедушка: Джон Родитель: Тед Ребенок: Мэри
Вот мой пример использования телефонного звонка для иллюстрации:
Джон звонит Теду и хочет провести конференц-связь с Мэри.
Тед говорит Джону: «Подожди, я позвоню Мэри»
Тед оставляет Джона на удержании и звонит Мэри, которая сразу же отвечает на звонок.
Мэри говорит Теду: «Соедините мой звонок с Джоном, и я НЕ буду вешать трубку, пока не закончу»
Тед, который долгое время не получал ответа от Джона, оставляет звонок, чтобы заняться чем-нибудь еще.
Джон идет объединить звонки с Тедом и Мэри, а затем внезапно умирает.
Мэри застряла на линии с Джоном, но никогда не повесит трубку, потому что Джон не вернется!
Цикл сохранения - это условие, при котором 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;
}
Вы не увидите журнал освобождения, это круг сохранения.
Так как объект P имеет значение keepCount, равное 1, когда он освобождается, его значение keepCount становится равным 0, и вызывается его метод dealloc; Это, в свою очередь, вызывает освобождение объекта C, счетчик удержания которого также становится равным 0; и вызывается его метод dealloc.
Оба объекта P и C будут освобождены.
Когда вызывается метод dealloc объекта C, в свою очередь вызывается освобождение объекта GP, но, поскольку GP содержит счетчик сохранения, равный 2, счетчик сохранения уменьшается до 1 и продолжает оставаться.
Цикл сохранения - это состояние тупика. Реальный пример цикла сохранения: если два объекта содержат ссылку друг на друга, и никакой другой объект не освобождается.
Пример: Рамми-игра
Когда два объекта сохраняют ссылки друг на друга таким образом, объекты создают цикл и сохраняются. Оба объекта пытаются удержать друг друга, в этом случае они сильно связаны друг с другом и невозможность высвободить называется циклом удержания.