Вопрос

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

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

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

NSMutableArray *removals = [NSMutableArray new];

но не похожий

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

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

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

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

и у меня нет утечек, и мне не нужно ничего публиковать.Кто-нибудь может объяснить?

Это было полезно?

Решение

Как отмечается в правила управления памятью, всякий раз, когда у вас есть объект, который вы создали с помощью +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, очень похоже на последний пример выше, но не обязательно.(Кстати, вы также можете создать пустой автоматически выпускаемый NSMutableArray с помощью [NSMutableArray array];метод находится в NSArray, поэтому он не будет отображаться в документации в разделе NSMutableArray, но он создаст изменяемый массив при отправке в класс NSMutableArray.) Если вы собираетесь возвращать массив из своего метода, вы можно использовать это как сокращение для [[[NSMutableArray alloc] init] autorelease]— но это всего лишь ярлык.Однако во многих ситуациях вы можете создать объект с помощью -init или +new и вручную отпустите его в нужное время.

Другие советы

Вот как все реализовано за кулисами:

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

и

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

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

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

Так:

NSMutableArray *removals = [NSMutableArray new];

Имеет параметр saveCount, равный 1, и:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

или

NSMutableArray *removals = [NSMutableArray array];

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

Вы берете на себя ответственность за объект, если вы создаете его, используя метод, имя которого начинается с «Alloc» или «New» или содержит «копию» (например, Alloc, NewObject или MutableCopy), или если вы отправите ему сохраняющее сообщение.Вы несете ответственность за отказ от владения объектами, которыми вы владеете, используя релиз или авторелюс.В любой другой раз, когда вы получаете объект, вы не должны его выпускать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top