Управление памятью при копировании объектов

#objective-c #memory-management #copy #retaincount

#objective-c #управление памятью #Копировать #сохранить количество

Вопрос:

Я знаю, что мой вопрос уже обсуждался в StackOverflow, но я нашел ответ неполным для моих нужд. Итак, вопрос в том:

 NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
secondArray = [firstArray mutableCopy];
  

какое количество сохранений для secondArray теперь? 2 или 1? Должен ли я выпускать его дважды или только один раз?
Сохраняется ли количество объектов КОПИРОВАНИЯ (в данном случае вторичного массива) при копировании или при увеличении изменяемой копии?

Ответ №1:

Вы никогда не должны заботиться об абсолютном количестве сохранений. Только то, что вы «сбалансированы», это означает, что для каждого alloc , new* , copy mutableCopy и retain вам нужно соответствующее release или autorelease (то есть, когда не используется ARC).

Если вы примените это правило к каждой строке, вы увидите, что во второй строке есть alloc , но нет освобождения. На самом деле, выделять экземпляр здесь абсолютно бесполезно, поскольку он вам все равно не интересен. Поэтому он должен просто читать:

 NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [firstArray mutableCopy];
// There is no third line.
  

Но давайте обсудим ваш исходный код и посмотрим, что получилось:

 NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
// secondArray points to a new instance of type NSMutableArray
secondArray = [firstArray mutableCopy];
// You have copied another array (created a new NSMutableArray
// instance) and have overwritten the pointer to the old array.
// This means that the instance allocated in line 2 is still there
// (was not released) but you don't have a pointer to it any more.
// The array from line 2 has been leaked.
  

В Objective-C мы часто говорим о владении: существует очень мало методов, которые делают вас «владельцем» объекта. Это:

  • alloc
  • new* , как в newFoo
  • copy и mutableCopy
  • retain

Если вы вызываете их, вы получаете объект, за который вы несете ответственность. И это означает, что вам нужно вызвать соответствующее количество release и / или autorelease для этих объектов. Например, все в порядке, если вы это сделаете [[obj retain] retain]; , а затем [[obj autorelease] release];

Комментарии:

1. Я бы добавил, что у вас есть два объекта, которые принадлежат и должны быть освобождены на каком-то этапе. И вы правы — retainCount это неважно — беспокоитесь только о балансировке вызовов владения с вызовами освобождения.

2. На самом деле secondArray был выделен и использован где-то далеко в коде. Я написал это во второй строке просто для удобства. Итак, если я правильно вас понял, чтобы избежать утечек памяти, я должен сначала выпустить secondArray, и это было бы абсолютно справедливо?

3.@AndreyChernukha: Вы освобождаете объект, на который указывает secondArray , только после того, как закончите с ним. release означает: начиная с этой строки, мне больше не понадобится этот объект; он может быть освобожден. autorelease означает: Скоро мне это больше не понадобится; но он должен оставаться активным, по крайней мере, до тех пор, пока я не оставлю этот метод. (Это не на 100% правильно, но достаточно близко к истине, чтобы быть полезным)

Ответ №2:

 NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
secondArray = [firstArray mutableCopy];
  

Происходит то, что вы создали утечку памяти. Вы только что потеряли ссылку, присвоенную secondArray, когда перезаписали ее изменяемой копией firstArray с помощью этой строки.

 secondArray = [firstArray mutableCopy];
  

Если вы затем дважды запустите secondArray, программа завершится сбоем, потому что вы переопределяете изменяемый массив, назначенный

 secondArray = [firstArray mutableCopy];
  

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