Setting objects to nil during fast enumeration [duplicate]

核能气质少年 提交于 2019-12-10 06:56:15

问题


I want to set an object to 'nil' as I enumerate through an array, as follows:

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

Xcode then tells me 'Fast enumeration variables can't be modified in ARC by default; declare the variable __strong to allow this.'

Which means doing this:

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

This seems to be redundant. As far as I understand, declaring a strong reference to an object increases its retain count by one, and nil-ing it decreases the retain count by one. So how, then, do I set an object to nil while enumerating through an array?

I am using ARC.


回答1:


See Fast enumeration iteration variables in the Clang "Objective-C Automatic Reference Counting" documentation:

If a variable is declared in the condition of an Objective-C fast enumeration loop, and the variable has no explicit ownership qualifier, then it is qualified with const __strong and objects encountered during the enumeration are not actually retained.

Rationale
This is an optimization made possible because fast enumeration loops promise to keep the objects retained during enumeration, and the collection itself cannot be synchronously modified. It can be overridden by explicitly qualifying the variable with __strong, which will make the variable mutable again and cause the loop to retain the objects it encounters.

So by default, the loop variable is immutable, and the retain count of the current object is not increased for performance reasons.

If you explicitly declare the loop variable as __strong, it is a mutable strong reference, and the retain count of the current object is increased, and setting the loop variable to nil decreases the retain count again. But doing so does not deallocate the object or remove it from the array, because the array holds another strong reference to the object.




回答2:


A shortcut:

[array removeAllObjects];

If you want your array to still contain x number of items but just not the items that are currently in it, you can use the NSNull placeholder:

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

Remember that the array only holds references to its objects. Memory management will kick in and deallocate the objects if the array no longer holds a reference to them (but only if nothing else does either).




回答3:


In the comments, you've revealed that your intention here is to deallocate the objects that are in the array whether or not something else also has an ownership claim on them. This is a violation of a core memory management principle: you must not free memory that you don't own. It is A Bad Idea to do what you want to do.

You must allow other objects to manage their own memory. Perhaps one of the items in the array is a piece of data that a UI object is displaying. When the UI object needs to refresh itself, and looks for the data which has been deallocated out from under it, your application will likely crash.

There are two things that you are allowed to do, from the perspective of this array. You can deallocate the array as a whole, which will give up the array's claims on the contained objects; if they are not owned by anything else, they will be deallocated. If you want to keep the array itself, but release all its items, use removeAllObjects; again, the items will be deallocated if nothing else owns them.

The important point is that if something else does own them, it's probably for a good reason, and you should not be doing an end run around it.



来源:https://stackoverflow.com/questions/14209076/setting-objects-to-nil-during-fast-enumeration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!