Установка объектов в ноль во время быстрого перечисления [дубликат]
На этот вопрос уже есть ответ здесь:
Я хочу установить объект в 'nil', когда я перечисляю через массив, следующим образом:
for(Object* object in array){
object = nil;
}
Затем Xcode говорит мне: "переменные быстрого перечисления не могут быть изменены в ARC по умолчанию; объявите переменную _ _ strong, чтобы разрешить этот.'
Что означает делать следующее:
for(Object __strong* object in array){
object = nil;
}
Это кажется излишним. Насколько я понимаю, объявление сильной ссылки на объект увеличивает его число удерживаний на единицу, а сведение к нулю уменьшает число удерживаний на единицу. Итак, как же мне установить объект в nil
при перечислении через массив?
Я использую ARC.
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
; опять же, элементы будут освобождены, если ими больше никто не владеет. Важный момент заключается в том, что если что-то другое действительно владеет ими, это, вероятно, по уважительной причине, и вы не должны делать конечную пробежку вокруг него.