Установка объектов в ноль во время быстрого перечисления [дубликат]


На этот вопрос уже есть ответ здесь:

Я хочу установить объект в 'nil', когда я перечисляю через массив, следующим образом:

for(Object* object in array){
    object = nil;
}

Затем Xcode говорит мне: "переменные быстрого перечисления не могут быть изменены в ARC по умолчанию; объявите переменную _ _ strong, чтобы разрешить этот.'

Что означает делать следующее:

for(Object __strong* object in array){
    object = nil;
}

Это кажется излишним. Насколько я понимаю, объявление сильной ссылки на объект увеличивает его число удерживаний на единицу, а сведение к нулю уменьшает число удерживаний на единицу. Итак, как же мне установить объект в nil при перечислении через массив?

Я использую ARC.

3 4

3 ответа:

Смотрите быстрое перечисление итерационных переменных в документации Clang "Objective-C Automatic Reference Counting":

Если переменная объявлена в условии Objective-C fast цикл перечисления, и переменная не имеет явного владения квалификатор, то он квалифицируется с помощью const __strong и объектов встречающиеся во время перечисления фактически не сохраняются.

Обоснование
Это оптимизация, ставшая возможной потому что быстро циклы перечисления обещают сохранить объекты сохраненными во время перечисление, и сама коллекция не может быть синхронно модифицированный. Его можно переопределить, явно определив переменную с __strong, что сделает переменную снова изменчивой и вызовет цикл для сохранения объектов, с которыми он сталкивается.

Таким образом, по умолчанию переменная цикла является неизменяемой, и число удержаний текущего объекта не увеличивается из соображений производительности.

Если вы явно объявите переменную цикла как __strong, это изменяемая сильная ссылка, и число удержаний текущего объекта увеличивается, и установка переменной цикла в nil снова уменьшает число удержаний. Но это не освобождает объект или не удаляет его из массива, поскольку массив содержит еще одну сильную ссылку на объект.

Короткий путь:

[array removeAllObjects];

Если вы хотите, чтобы Ваш массив по-прежнему содержал x элементов, но только не те элементы, которые находятся в нем в данный момент, Вы можете использовать заполнитель NSNull:

for (NSUInteger i = 0; i < [array count]; i++)
    [array replaceObjectAtIndex:i withObject:[NSNull null]];

Помните, что массив содержит только ссылки на свои объекты. Управление памятью включится и освободит объекты, если массив больше не содержит ссылки на них (но только если больше ничего не делает).

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

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

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