Подтвердить что ты не робот

Объективная версия C, автореферат и типы данных

Я новичок в коде, управляемом памятью, но я хорошо понимаю эту идею.

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

Затем я заметил нечто особенное: я получил утечку на определенном массиве, инициализированном следующим образом:

NSMutableArray *removals = [NSMutableArray new];

но не аналогичный

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

Теперь причина, по которой была настроена "новая", состоит в том, что она может содержать 0-99 элементов, тогда как другая, я знал, всегда будет 9. Поскольку оба массива передаются одному и тому же методу позже основанный на взаимодействии с пользователем, я либо получал утечку, если не был выпущен в конце метода, либо исключение, если бы я это сделал!

Я изменил первый массив на

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

и я не получаю утечек и не должен ничего отпускать. Может кто-нибудь объяснить?

4b9b3361

Ответ 1

Как отмечено в правилах управления памятью, всякий раз, когда у вас есть объект, который вы создали с помощью +alloc, +new, -copy, или -mutableCopy, вы владеете им и несете ответственность за его выпуск в какой-то момент. (На самом деле +new является только сокращением для [[MyClass alloc] init].) Как вы отметили, создание массива через [NSArray new] без его выпуска утечка памяти. Однако, если вы правильно обрабатываете этот объект, его можно в любой момент выпустить. Например:

  • Если метод использует, массив вызывается из внутри метода, который создает массив, то вы должны иметь возможность выпускать массив после того, как он были использованы. Если внутренний метод должен поддерживать более постоянную ссылку на массив вокруг, то этот метод отвечает за отправку объекта -retain и, в конечном итоге, -release. Например:

    - (void)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        [someObject someOtherMethod:removals];
        [removals release];
    }
    
  • Если вы создали массив в -init метод для объекта, то метод -dealloc может освободить его, когда объект будет уничтожен.

  • Если вам нужно создать массив, а затем вернуть из этого метода, вы обнаружили причину, по которой было изобретено автореализацию. Вызывающий ваш метод не несет ответственности за освобождение объекта, так как это не метод +alloc, +new, -copy или -mutableCopy, но вы должны убедиться, что он выпущен в конце концов. В этом случае вы вручную вызываете -autorelease объекта перед его возвратом. Например:

    - (NSArray *)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        return [removals autorelease];
    }
    

Когда вы создаете массив через +arrayWithCapacity:, вы не вызываете один из "специальных" методов, поэтому вам не нужно выводить результат. Вероятно, это реализовано с помощью -autorelease, как и в предыдущем примере выше, но не обязательно. (Кстати, вы также можете создать пустой autoreleased NSMutableArray с [NSMutableArray array], метод найден в NSArray, поэтому он не будет отображаться в документации под NSMutableArray, но он будет создавать измененный массив при отправке в класс NSMutableArray. ) Если вы собираетесь возвращать массив из вашего метода, вы можете использовать его как сокращение для [[[NSMutableArray alloc] init] autorelease], но это просто ярлык. Однако во многих ситуациях вы можете создать объект с помощью -init или +new и вручную отпустить его в соответствующее время.

Ответ 2

Вот как это реализовано за сценой:

+(NSMutableArray*) new
{
    return [[NSMutableArray alloc] init];
}

и

+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
{
    return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
}

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

Ответ 3

Cocoa использует определенные соглашения об именах. Все, что начинается с alloc, new или copy, возвращает что-то с saveCount 1, и вам необходимо освободить. Все остальное, что возвращает функция, имеет сбалансированное значение keepCount (оно может удерживаться чем-то другим, или оно может быть сохранено и освобождено).

Итак:

NSMutableArray *removals = [NSMutableArray new];

Имеет значение saveCount из 1 и:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

или

NSMutableArray *removals = [NSMutableArray array];

Не следует, поскольку методы не имеют префикса с помощью alloc, new или copy. Все это описано в управлении памятью documentation. В частности:

Вы берете на себя ответственность за объект, если вы создайте его, используя метод, чье имя начинается с "alloc" или "new" или содержит "копию" (например, alloc, newObject или mutableCopy), или если вы отправьте сообщение сохранения. Вы ответственный за отказ владение собственными объектами релиз или автореферат. В любое другое время вы получаете объект, вы не должны отпустите его.