Предупреждение «Потенциальная утечка объекта, выделенного в строке …» при объявлении 2D-массива

#objective-c

#objective-c

Вопрос:

Изначально я объявил 2D-массив таким образом:

 subUrb = [[NSArray alloc] initWithObjects:
     [[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"East",@"South", @"West", @"North", nil] ,
     [[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"Kuala Lumpur SubUrb1", @"Kuala Lumpur SubUrb2", nil],
     [[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"Jakarta SubUrb1",nil],
     nil]; 
  

Но когда я пытаюсь «проанализировать» предупреждения проекта, я получаю три однотипные проблемы в этом фрагменте кода — «потенциальная утечка объекта, выделенного в строке xxx»

Я заметил, что для того, чтобы избавиться от этого, я должен написать что-то вроде этого:

 subUrb = 
    [[NSArray alloc] initWithObjects:
        [[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"East",@"South", @"West", @"North", nil] autorelease],
        [[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"Kuala Lumpur SubUrb1", @"Kuala Lumpur SubUrb2", nil] autorelease],
        [[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"Jakarta SubUrb1",nil] autorelease],
        nil];
  

Тогда я не получу никаких предупреждений analyze. Но мне не нравится this…it не логично. Этот 2D-массив никогда не должен быть выпущен в моем контроллере на самом деле, весь 2D-массив должен быть сохранен в течение всего срока службы контроллера для pickerView.

Как мне следует более элегантно объявить 2D-массив?

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

1. мой окончательный код: subUrb = [[NSArray alloc] initWithObjects: [NSArray arrayWithObjects:@"East",@"South", @"West", @"North", nil] , [NSArray arrayWithObjects:ALL_SUBURBS_LABEL, @"Kuala Lumpur SubUrb1", @"Kuala Lumpur SubUrb2", nil], [NSArray arrayWithObjects:ALL_SUBURBS_LABEL, @"Jakarta SubUrb1",nil], nil ];

Ответ №1:

1: NARC

Если вы отправляете alloc , вы являетесь владельцем этого объекта, и вы несете ответственность за его освобождение. Следовательно

 [[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, @"East",@"South", @"West", @"North", nil]
  

создает массив, который принадлежит вам, следовательно, вы должны освободить его.

2. Коллекции Cocoa владеют своими элементами

Когда вы добавляете объект в коллекцию Cocoa, такую как NSArray , коллекция владеет этим объектом. Это также приведет к освобождению всех элементов в коллекции, когда они больше не используются.

3: Заключение

Ваш код без этого -autorelease предоставляет вам право собственности как на самый внешний массив, так и на каждый внутренний массив, который является элементом самого внешнего массива. Это означает, что вы несете ответственность за освобождение этих четырех массивов (один самый внешний, три самых внутренних). Однако, поскольку самый внешний массив уже владеет самыми внутренними массивами, вам, вероятно, также не нужно владеть ими, следовательно -autorelease .

Ответ №2:

Вы получаете право собственности, если выделяете массив с помощью alloc init, и поэтому вам нужно освободить его, как вы делаете во втором коде. Вы также можете использовать: [[NSArray alloc] initWithObjects:
[NSArray arayWithObjects:first,second, nil], nil];

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

1. спасибо, это последний метод, который я использовал. alloc initWithObjects для внешнего массива и arrayWithObjects для внутренних массивов

Ответ №3:

Ваш второй метод верен. Дело в том, что объемлющий массив получит право собственности на вложенные объекты, в то время как дополнительное право владения, которое вы получаете через alloc , остается зависшим. Несколько более аккуратный подход заключается в использовании метода класса arrayWithObjects вместо alloc / initWithObjects / autorelease , но это означает то же самое.

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

1. Обратите внимание, что вам не нужен автоматический выпуск с помощью arrayWithObjects, потому что массив уже автоматически выпущен и не принадлежит вам, поскольку имя метода не содержит alloc, retain или copy (что означает, что он принадлежит вам).

2. спасибо за ответ. я использовал arrayWithObjects, чтобы сделать его «немного аккуратнее»: D

Ответ №4:

Даже если массив необходим в течение всего срока службы контроллера, вы должны освободить его с помощью метода dealloc контроллера, в противном случае произойдет утечка объектов.

Ответ №5:

Если он никогда не будет выпущен, то оба способа утечки не будут, но второй более «правильный». NSArrays не будут автоматически выпущены до тех пор, пока родительский массив не будет (никогда), так что все в порядке.

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

1. На самом деле, вложенные массивы будут автоматически выпущены довольно скоро — но они все еще будут сохранены во вложенном массиве.

Ответ №6:

Когда вы добавляете дочерний массив к родительскому массиву, родительский массив сохраняет дочерний массив. Таким образом, количество сохранений увеличивается до 2. Поскольку вы нигде больше не сохраняете ссылку на дочерний массив (ы), количество сохранений должно быть только 1, следовательно, вам следует использовать авторелиз. Итак, ваша вторая версия верна.

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

1. Пожалуйста, не говорите о количестве сохранений при дочерних элементах.

2. @dunforget @Twelve47 извините, хотел показаться забавным школьником, возможно, просто прозвучал как покровительственный и ехидный. Однако суть остается: количество сохранений — это зло, отводите глаза!

3. @walkytalky Я не согласен, если вы используете сохранение и (автоматическое) освобождение, вы должны понимать, что они делают.