Управление памятью в Objective-C, инициализация нового массива в автоматически освобожденный массив из другой функции

#iphone #objective-c #memory-management

#iPhone #objective-c #управление памятью

Вопрос:

Я пытаюсь лучше понять управление памятью. Если у меня есть функция, которая возвращает автоматически освобождаемый NSArray, подобный этому

 // DataClass
    - (NSArray *)getData {
       NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
       // do some stuff to get data from sqlite
       return array;
    }
  

затем в другом файле класса я хочу использовать этот getData . У меня есть свойство

 @property (nonatomic, retain) NSArray *myData;

- viewDidLoad {
    NSMutableArray *data = [[NSMutableArray alloc] init];
    data = [DataClass getData];
    self.myData = data;
    [data release];
}
  

Почему в этом случае я получаю ошибку bad access? Я знаю, что это из-за [освобождения данных], но я подумал, что, поскольку метод getData возвращает автоматически освобождаемый NSArray, и поскольку я инициализирую новый NSMutableArray с помощью alloc / init, тогда мне нужно будет его освободить? Или происходит то, что, хотя я инициализирую данные с помощью alloc / init, я даже не использую его, потому что с помощью инструкции data=[DataClass getData] я указываю на другой NSArray, а затем пытаюсь освободить этот уже автоматически освобожденный NSArray из getData, а затем данные NSMutableArray все еще плаваютгде-то в памяти? Заранее спасибо.

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

1. Этот код может быть записан как self.myData = [DataClass getData]; .

Ответ №1:

Ваше предположение верно. 🙂

Прежде всего, как написано, в viewDidLoad вас утечка data вы выделяете / инициализируете в строке 1, когда вы присваиваете data результат вызова getData в строке 2.

И тогда, вы правы, то, что data в данный момент указывает на автоматически выпущенный объект. Так что обращение release к нему — это плохо.

Честно говоря, в вашем viewDidLoad методе вам вообще не нужен вызов to getData . Полная и подходящая последовательность для такого рода операций:

 NSMutableArray *array = [[NSMutableArray alloc] init];
// here is where you could fill array with your data, or call a method to 
// which you pass array to be filled.
self.data = array;
[array release];
  

предполагая, что свойство data определено с retain помощью . Используя self. префикс, вы получаете retain результат за себя.

Помогает ли это?

Ответ №2:

С вашим кодом возможны две проблемы. Первое несомненно:

  NSMutableArray *data = [[NSMutableArray alloc] init];
 data = [DataClass getData];
  

Это неправильный шаблон для инициализации объектов. Давайте предположим, что вызываемый метод класса getData существует и делает то, что вы хотите (что может быть не так, подробнее об этом позже). Первая строка выделит память для нового массива и вернет указатель на него. Затем вторая строка немедленно переназначит этот указатель, чтобы указать на другой (автоматически освобожденный) массив, пропуская первый массив в процессе.

Во-вторых, ваш getData метод имеет следующую подпись:

 - (NSArray *)getData;
  

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