release and retain
Let's say I do the following (foo starts out as some object):
[foo release];
// STUFF with foo
[foo retain];
As long as I'm not re-assigning foo, at the end of this I'll still have the same foo, right? I'm not risking losing foo during the //STUFF am I?
I guess I'm making sure that my understanding of release is correct. If I release foo, it doesn't actually go away until all handles on it are gone. In other words, foo would have to be assigned to some other object in the //STUFF, or foo would have to go out of scope in the //STUFF (and presumably have a new foo created) in order for the actual original foo object to be deleted, right?
EDIT for motivation:
The reason I want to do this is that lets say I have the following switch statement:
switch (test)
{
case 1:
foo = [A alloc];
[foo inita];
break;
case 2:
foo = [B alloc];
[foo initb];
break;
case 3:
[foo setu开发者_Python百科pc];
break;
case 4:
f = [D alloc];
[foo initd];
break;
}
It makes sense to release foo before the switch and retain it at then end. EXCEPT for case 3. So, I was thinking that if was safe to do what I proposed, it might make the code simpler.
Of course I can just put a release/retain pair around each alloc/init, but that's a lot of replicated code...
A [foo autorelease] and then the retain might just do the trick.
Nope, here's what happens:
The -release
method decrements the retain count and then checks to see if it's now zero. If the retain count is zero, -release
calls [self dealloc]
, which causes the object to be deallocated immediately. So sending -release
before sending a -retain
message would not be a good idea given your example, and would be likely to crash your app.
Based on your added comments, here's an alternative way to write the code that I think will do what you want while avoiding code duplication:
Class class = Nil;
// Decide which class (if any) to use...
switch (test)
{
case 1: class = [A class]; break;
case 2: class = [B class]; break;
case 3: class = foo == nil ? Nil : [C class]; break;
case 4: class = [D class]; break;
}
// If a class was selected, create a new instance
// and release the previous one...
if (class != Nil)
{
[foo release];
foo = [[class alloc] init];
}
Note that there's no need for a -retain
here because as I mentioned previously, +alloc
sets the retain count to one.
If the retain count of foo
goes to zero at the beginning of that code, it will get obliterated and stop working. Use autorelease
if you want to do something like that. release
is a no-op in garbage collected environements, according to the docs - maybe that's what you're thinking of?
All release
does is decrement the reference counter, which every object has.
I'm not sure why you'd want to release
and retain
like you've shown, though.
Yes, you most definitely are risking "loosing" during STUFF
in a reference-counted (non-GC) environment. If your first -release
decrements foo
's reference count to 0, it will be deallocated. Continuing to use foo
in this case is venturing into undefined behavior, and you will almost certainly pay the price eventually. In other words, there be dragons here. It might work in the case that you (and any other frameworks you call) don't allocate any memory during STUFF
which overrites the allocated instance that foo
referenced and the instance pointed to by foo
's -dealloc
method doesn't change foo
's state except for releasing instance variable reference and smashes the memory occupied by those references and so on. In this case, your code might work as if foo
hadn't been deallocated, but that's only luck.
In a garbage-collected environment, you're safe. Because you hold a reference to foo
through STUFF
, and because -release
and -retain
are no-ops in a GC environment, foo
will still be valid.
精彩评论