Objective-C Difference between setting nil and releasing - objective-c

I've learned that in dealloc you do [object release]; but in viewDidUnload (in a UIViewController subclass) you do self.object = nil. What is really the difference because self.object = nil (we're assuming object is a (nonatomic, retain) property) retains nil (which does nothing) and then releases the old value and then the reference count is 0 right?

self.object = nil calls your setter, which will release the old value, set the member to nil, and possibly do other things (it's a method, so it could do anything). The "anything" part of that is potentially dangerous; see this question, for example.
[object release] releases the old value, but leaves the member as a now-dangling pointer, which is a good recipe for bugs. In dealloc it doesn't really matter, since the pointer itself is about to go away too, but in any other case it's a very bad idea to release a member without setting it to nil.
(As a sidenote, you should never assume that releasing an object gives it a reference count of 0. It releases your reference, but other objects may still have references to it.)

If you do object = nil without [object release], that might causes memory leaking. If you do [object release] without object = nil afterwards, object becomes dangling pointer as #Jim suggested. self.object = nil is a sugar for setter function call.

If you just release an object, then it will become freed object.
And if you try to perform any sort of operation on freed object then your app crashes. To avoid such accidents, it is always preferred "assign your object to nil after releasing it". Because we all know any operations performed on nil will not be executed :)

If you do [object release], and want to access the object the app simply crash.
If you do object = nil, and want to access the object nothing will perform.
The reason is in the [object release], you are attempted to free the object. so its dont have any pointer (no memoty).In the object = nil, you are attempted to assign the object with null pointer. so if u trying to access the object nothing will happen.
Generally we wrote the code as [object release]; object = nil; because if u access the object unexpectedly, the app wont crashed.

Related

arc, strong and weak instance variables

Just trying to fully understand ARC.
MyView *testView = [[MyView alloc] init];
__weak MyView *weakView = testView;
[weakView addObserver:self forKeyPath:#"alpha" options:0 context:nil];
testView = nil;
if(weakView) {
NSLog(#"WeakView exists!");
}
I don't understand why my NSLog statement is printing. Since weakView is a weak reference to testView, shouldn't it be pointing to nil once testView is set to nil???
Thanks!
The addObserver method seems to retain and autorelease the view. Thats why the weak reference is not zeroed right after the initial reference is nilled. Just run this code in the debugger:
UIView *testView = [[UIView alloc] init];
__weak UIView *weakView = testView;
#autoreleasepool {
[weakView addObserver:self forKeyPath:#"alpha" options:0 context:nil];
}
testView = nil;
if(weakView) {
NSLog(#"WeakView exists!");
}
It may or may not. It goes to nil when the object is deallocated. The fact that you set testView to nil only implies that you are releasing the object. But the object is not guaranteed to immediately be deallocated.
The problem here is that you are assuming a given value for the retain count. You think that the alloc+init sequence gave you an object with a count of 1 so that when you set testView to nil it goes to 0 and the object is deallocated.
You should never assume a given retain count. You should always think in terms of relative retain counts. The alloc+init sequence returns a +1 object (not 1 but +1). When you set set testView to nil ARC calls release and turns it to a +0 object (not 0, but +0). This means you have no guarantee that it's still accessible. Your weak reference may or may not be valid.
What is in fact happening is that internally in the init method (or the chained init methods of the parents) there has been a call to autorelease therefore your object does not yet have a refcount of 0. It will get it (and be deallocated) at the next pool drain.
Edit:
Also what Adam says in his reply is correct.
Your testView is local variable and local variables under ARC doesn't have precise lifetime semantics. Read 6.1 at:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#optimization.precise
What does it mean? This means that the compiler can do whatever it wants to do.
Current implementation releases testView object at the end of the method. But what if the optimizer (now, future, ...) decides that the lifetime is over and it will release it sooner (before the end of the method)?
In other words, you're trying to depend on undefined behavior. Don't do this, don't rely on this. In this case, you never know when the object is really released = weak reference is zeroed.

What will happen to this object

I have created one firstObject with the help of secondObject. Now I am released that secondObject what will happen to the firstObject.
Here is my code.
SecondObject *secondObject = [[SecondObject alloc]init];
FirstObject *firstObject = [[FirstObject alloc]initWithSecondObject:secondObject];
[secondObject doSomethings];
[firstObject doSomeThings];
[secondObject release];
Unless secondObject has a reference to firstObject which it releases, nothing will happen to firstObject.
If firstObject needs to keep a reference to secondObject beyond it's initWithSecondObject: method, it should retain secondObject. That will prevent secondObject from being deallocated even though you're releasing it in the code above. When you release an object, you're saying: "I'm done using this." But the object will only be deallocated if no other object is currently using it (as determined by the retain count, not that you should be looking at that).

self.property to nil vs [ivar release] case close

There have been a lot of discussions on why you should not use setter in dealloc like you do in viewDidUnload. Question is, why not just use [property release] in both dealloc or viewDidUnload? Doesn't that end the discussion or is there a reason why one should do self.property = nil in viewDidUnload instead?
That is, we always follow this idiom for everything - rather than using one form in viewDidUnload and another in dealloc, which seems senseless.
[ivar release];
ivar = nil;
The general idea is that nothing will happen with an object after dealloc, so you can just release property and don't worry about it being invalid pointer. On the other hand, if you do [property release] in viewDidUnload and not set it to nil, it will contain invalid pointer and this may lead to crash if property is used before new valid value assigned to it.
Properties are save for this, you can set nil them everywhere, because them save releasing (setters are looking like -(void)setProp { [prop release]; self.prop = nil; }).
But if you use [something release], you should do it in viewDidUnload method, because view can be unloaded, but controller not deallocated, which means possible memory leak in viewDidLoad. And if you call [something release] twice, it will cause crash for wrong counter decrease
All the other responses consider the two ways the same. But consider when you have an atomic property. It's a lot shorter and cleaner than the "pure" way.

NSString being released even after being retained

I have an NSString that I've retained, and the only place I release it is in the dealloc method. For some reason, however, later in the program when I try to reference it (its length, specifically), I get a crash, saying [CFString length]:message sent to deallocated instance 0xff32c50.
I explicitly retain the string earlier in the program. Is there any reason why this would be happening? Any help is appreciated.
The string, entityParameter, is declared in the header, and defined later.
Here is some of the code:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
The place where I'm getting the crash looks like this:
if([entityParameter length] != 0 && entityParameter != nil)
{
return;
}
I have an NSString that I've retained,
and the only place I release it is in
the dealloc method. For some reason,
however, later in the program when I
try to reference it (its length,
specifically), I get a crash, saying
[CFString length]:message sent to
deallocated instance 0xff32c50.
Obviously, it isn't retained, then.
If by "retained" you mean "assigned to a property", are you doing:
self.prop = [NSString ...];
Or:
prop = [NSString ...];
Because the former will retain (if the property is declared as retain) whereas the latter will not. Note that NSString properties should generally be declared copy, but that is orthogonal to the question).
If your code is as written:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
And you really do only release it in dealloc, then make sure your containing object hasn't already been deallocated. That may be happening. Or it might be that you've leaked the string reference somewhere and spuriously deleted it without a retain.
Using Zombie detection in instruments with "track retain/release events" (or whatever it is called) should show you every last retain/release event on the object, including the one the blew up.

Why setting to nil after releasing?

I came across this method:
-(void) someMethod {
NSMutableArray *anArray = [[NSMutableArray alloc] init];
// Do stuff with anArray ...
[anArray release];
anArray = nil;
}
Is setting the array to nil necessary?
In this code by sending a release message to the array, it will causes the array to be deallocated.
In this case, it is a pointless waste of key strokes because the variable anArray goes out of scope immediately.
In other cases, where the variable stays in scope for a while after you release the object its pointing to, it is a good idea, because, if you accidentally dereference it, you will get a EXC_BAD_ACCESS which is easy to spot, and if you send a message to it, it will be ignored (except for returning nil / 0).
As others have mentioned, setting it to nil will help your code not crash if you reference the dealloced object. If you reference a dealloced you will get EXC_BAD_ACCESS error and your app will crash. Since a nil object returns nil if a message is sent to it, your app will not crash.
In the example you provide, it is not necessary to nil it out, since it is contained in a method. However, you do not want to nil out a variable if you expect to use it somewhere else in the code, since the value will then be nil.
No it is not necessary.
It is just for safe reason (to not send a message to a zombie)
And you can test if your ivar is nil or not to realloc:
[ivar release];
ivar=nil;
...
if (ivar==nil) {
ivar = [[NSObject alloc] init];
}
[ivar setValue:#"toto"];
It's not necessary but considered good behaviour to set dangling pointers to nil.