iPhone: What deallocates something? release until owner is 0 or nil?
I'm still a tad confused on iPhone memory management. It's not a huge issue as it doesn't deal with the most common use cases (I just release in dealloc, and set to nil in viewDidUnLoad). But let's get this straight:
Suppose I got an instance variable that is retained and synthesized. And I allocate it.
If I set it to nil, does that mean the object is deallocated in memory? It's gone? Because someone told me setting it to nil only sets the pointer to nil, and doesn't deallocate it from memory.
I know when the owner count is set to 0, the memory is deallocated.. That's correct, right? If not, I think my entire开发者_JS百科 universe may have been broken =)
When a piece of memory has a retain count of 0 associated with it, then it is available for reuse (so it is deallocated).
Suppose I got an instance variable that is retained and synthesized. And I allocate it.
In your .h file:
@property (nonatomic, retain) SomeObject myInstanceVariable;
In your .m file:
@synthesize myInstanceVariable;
self.myInstanceVariable = [[SomeObject alloc] init];
This statement does two things - firstly it allocates memory for "SomeObject" and in the process sets the retain count on that memory to 1. Secondly it assigns a pointer to that memory to the ivar via the synthesized setter method. The synthesized setter method calls release on any current memory pointed to by the iVar, which reduces its retain count by 1, and then assigns the pointer to the new object to the iVar and increments its retain count. Thus after this statement the retain count is 2
If I set it to nil, does that mean the object is deallocated in memory? It's gone? Because someone told me setting it to nil only sets the pointer to nil, and doesn't deallocate it from memory.
self.myInstanceVariable = nil;
This sets the iVar via the synthesized setter method, which reduces the retain count of the current value by 1 and then sets the new value (nil) on the iVar. Thus in this example these two statements one after the other result in memory that still has a retain count of 1 and thus is not available for reuse by the operating system.
So if you allocate an object yourself and then also assign it to a retain property, then you should explicitly release it after assigning it to the retain property. (and in your dealloc method also release the ivar to cater for the property).
self.myInstanceVariable = [[[SomeObject alloc] init] autorelease];
this allocates some memory (increasing its retain count to 1) then assigns a pointer to that memory to the iVar via the setter (increasing the retain count to 2) but also flags it for autorelease - which means it is added to the autorelease pool and released when your thread loses control (which will reduce the retain count by 1). Then when your object (self) is released, the dealloc method (if implemented properly) will release the ivar (myInstanceVariable) and then the retain count will go to 0 and the memory you originally allocated will be deallocated.
If I set it to nil, does that mean the object is deallocated in memory? It's gone? Because someone told me setting it to nil only sets the pointer to nil, and doesn't deallocate it from memory.
There are two parts to this:
If you set your instance variable to nil without prefixing it with the self
keyword, you're referencing the instance variable directly. You don't get any of the memory management stuff for free when this happens. This means you'll leak the reference that was assigned to it if you don't explicitly release the reference by calling its release
/autorelease
method.
Object *ivar = [[Object alloc]init];
ivar = nil;
In this case, you'll leak the Object reference since you're not explicitly releasing it. To correct this, you'd want to do something along the lines of:
Object *ivar = [[[Object alloc] init] autorelease];
ivar = nil;
where the reference would be autoreleased at the end of the run loop when the runtime detects that it's no longer referenced. Or
Object *ivar = [[Object alloc]init];
[ivar release];
ivar = nil;
where you explicitly release the object and set it to nil. You do this to ensure that the instance variable isn't pointing to some junk in memory that could have been claimed by something else after it was released.
If you don't release the reference and only set the instance variable to nil, you'll lose the handle to the reference. When this happens, it'll continue to sit in the application's working set as allocated memory. You've got no handle to this segment in memory and no way of getting one. It'll stay there until the application terminates. This is a leak.
If you set your instance variable to nil with the self prefix, you're assigning a nil value to the property. Depending on how the property is declared, this could either mean that the previous reference is released (retain
/copy
) or leaked (assign
).
@property (nonatomic, retain) Object *o;
self.o = [[[Object alloc]init]autorelease];
This allocates space for an Object, assigns it to a property named o, which retains it (as indicated in the property definition). You're still responsible for releasing the object that you created, so you need to explicitly release it. I chose to autorelease it but you could very well release it. Once you're done with this property, typically in the dealloc method of the containing scope, you release it. You can also set it to nil.
I know when the owner count is set to 0, the memory is deallocated.. That's correct, right?
Yes. But you shouldn't worry about the retain count. You should worry about releasing all objects that you explicitly alloc
, new
, copy
, or retain
in the scope that you've performed the aforementioned action(s). If you do this, you'll be fine.
If you are setting an ivar to nil, that does not call release on it. If you set a property to nil, the @synthesized code will call release on the ivar before setting it to nil. When the reference count is 0, the object will be deallocated.
If you are setting an ivar to nil, that does not call release on it. If you set a property to nil, the @synthesized code will call release on the ivar before setting it to nil. When the reference count is 0, the object will be deallocated.
Nathanial Woolis's answer above is not exactly correct and misleading. If you have an ivar and @property
set to retain
, or copy
, it will be released for you with the default setter of self.foo = nil
; If you use assign
instead it will not be released for you in the setter. Check here for more info on properties, specifically the Setter Semantics
section
Assuming that your ivar is set to retain
in the property setting, then you "own" its contents. But if you set it to "nil" you are clearing those contents, and while a pointer still exists, you have essentially made available the memory that was used before. In fact, the dot notation, such as self.ivar=nil
, does I believe perform a release on the ivar first before re-assigning it to the value you specify, in this case nil. This is a built-in mechanism in objective c to avoid memory leaks every time you re-assign an ivar property.
精彩评论