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

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.

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.

Basic memory management confusion

I bet that I could find the answer of this question from reading similar threads here or by googling, but I would like "hear" it first hand so to speak because it's an anomaly in my understanding.
So here's the thing, I have some code which a previous employee wrote and I see a lot of a certain type of construct which looks rather odd to me and I just want to clarify what is "right and wrong".
For example
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
Here wwanServiceIdis a NSString member of the class, and to me this seem like a strange way to do it. As far as I understand it would begin by putting an autorelease on the object, basically saying: "whenever this object seem to not be used, release it for me I don't really care" then the copy will up the retain count +1 on.... wwanServiceId? or newValue? I guess the first.
Then to make me all more confused let's just quickly run through the life-cycle of the wwanServiceId-string..
basically the value will be set if we receive a notification which then from the notification-handler method will call the above -setWwanServiceId: method. other than that it will only ever be accessed for reading, so we are safe to say that it will at any given point:
put autorelease on object
retain a new string copy
Then there is one more quirk to this and this is where I am getting rather suspicious, namely in the -dealloc method which looks like this:
- (void) dealloc {
[[self wwanServiceId] release];
[super dealloc];
}
So what happens there? it will afaik release the wwanServiceId and as I said the only time it's memory management is being touched (if I haven't missed anything but I feel pretty sure) is to put an autorelease and retain it.
So to summarize:
Is the idea here that he thought that since he always retain a new copy after putting autorelease he need to release it in the end.. or well it's the only thing I can think about. Or just felt it would be safe to do an extra release in the end just in case..?
Because as far as I understand it, if this setter is called one time it will put an autorelease (-1 in future), do a retain (+1) and when destructor is called it will do the "final release" (-1).
Any ideas or suggestions helping me understand (if in fact I am wrong and the memory handling is correct as is) would be appreciated.
You wrote:
Here wwanServiceIdis a NSString member of the class, and to me this seem like a strange way to do it. As far as I understand it would begin by putting an autorelease on the object, basically saying: "whenever this object seem to not be used, release it for me I don't really care" then the copy will up the retain count +1 on.... wwanServiceId? or newValue? I guess the first.
This seems to point to the source of your confusion. wwanServiceId is a variable which can contain a reference to an object of type NSString. Variables do not have reference counts only objects do.
The previous employee wrote:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
The expression [wwanServiceId autorelease] means: read the reference stored in wwanServiceId and autorelease the object that reference refers to - let's call that object A. Important: This does not delete object A; it will be released as some later stage and if at that time there are no remaining references object A will be deleted.
The expression [newValue copy] means: read the reference stored in newValue, use that to locate the object (call it object B), make a copy of that object to produce a new object (call it object C), and return a reference to the new object. This new object is owned by the caller of copy, so there is no need to retain it.
Finally the assignment stores the reference to object C into wwanServiceId.
So there is a maximum of three distinct objects involved:
A: the original object referenced by wwanServiceId, this is autoreleased to remove the ownership of wwanServiceId.
B: the object referenced by newValue, this is left untouched
C: a newly created copy of B owned through wwanServiceId
Why "autorelease" in the code and "maximum of three distinct" above?
The method could be called with newValue referencing object A, e.g. as in:
[self setWwanServiceId:[self wwanServiceId]]
If this was to occur and (a) release was used instead of autorelease and (b) there was no other reference to object A then the release would delete object A and then when [newValue copy] was evaluated newValue would be referencing a deleted object... The use of autorelease in this case delays the deletion until after the copy.
So what the previous employee wrote is not in any way "wrong", but as some of the other answer suggest it may be an unusual style. Another way you see this written is:
- (void) setWwanServiceId: (NSString *) newValue
{
NSString *oldValue = wwanServiceId;
wwanServiceId = [newValue copy];
[oldValue release];
}
which also ensures any deletion occurs after the copy.
HTH.
To be short and helpful:
This is wrong:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
This is right:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
To explain in short:
[wwanServiceId autorelease]; is an unnecessary sent message, because autoreleasing an object will reduce the retain count at some unknown point in the future. And in the next line you are wwanServiceId = [newValue copy]; instantly setting the instance variable. So, in your memory you now have a to be autoreleased object and a new object. One of them is too much The new object is, where the pointer of your IVar is pointing to. The old one is swimming in your Memory Pool with probably no reference to it :-)
Autorelease as few as possible or use ARC.
Oh: And in the dealloc method, please do not send the message like this:
[[self wwanServiceId] release];
Better like this:
[wwanServiceId release];
as Apple recommends to work directly with instance methods in init and dealloc methods, instead of using getters and setters there.
Debug it and have a look.
[wwanServiceId autorelease];
wwanServiceId has an address. This statement does not change it. It does decrement the retain count of this object though.
Thats it.
wwanServiceId = [newValue copy];
This statement creates a new object. The new object is a copy of newValue. Compare the addresses of the objects and you will see, that the address inn wwanServiceId will vary from the address of newValue and it will vary from the address that wwanServiceId did have just before the statement was executed.
The retain, that is implicit in copy will affect wwanServiceId, but it affects the new object, that was just creaed with copy. It does not affect the wwanServiceId object which was autoreleased during the statement before.
At some point after the execution of setWwanServiceId had finished, the old and autoreleased object will dissappear. (Assuming that the retain count is 0 now. If it is >0 because it is still retained for other reasons or just for error, then it will remain and potentially cause a leak.)
Once you understood that you will not question any more what is happening in the dealloc method. wwanServiceId is released. Meaning its retain count is reduced by 1. In the event that it is 0 then it will be deallocated automatically.
You could even autorelease it there too. The diffrerence to autorelease is basically that an autoreleased object is still around and available while the current method is being executed. Its release comes into effect at some later point in time.
But there is no reason for autoreleasing the object in dealloc.
In the example given there is not even a good reason to autorelease the object in the setter setWwanServiceId. You may well release the object directly in both methods.
Assuming wwanServiceId is the private ivar mapped by the getter wwanServiceId and setter setWwanServiceId, I think it is not correct to autorelease the ivar in the setter.
I would have coded the following:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
What I mean is: it is not necessary to give ownership of your var to the autorelease pool (which it may be drained at the end of the application). Simply release the ivar. If someone is using it, no problem, it will have a strong reference to it. Otherwise it will be deallocated.

Should I retain a object pointer parameter in every method?

I am trying to get the hang of retain / release. I get that they are a matched set. But I don't know when I have to retain references.
-(void)sampleMethod:(RandomClass *) obj {
[obj retain];
// Do stuff to object...
[obj release];
}
Is it necessary to retain (and thus release) obj?
I am worried about obj going away. Does it follow that you must (if) retain reference parameters as soon as possible in the function? What about the space of time between the functions call and the first instruction of the function?
Thanks!
Short answer; use ARC.
Joe's answer is more or less correct. Until it isn't.
In general, there is no need to retain arguments or return values from other methods. However, the resulting code only works by coincidence and convention, not by algorithmic analysis.
Consider:
NSString *foo = [aMutableArray objectAtIndex: 5];
[aMutableArray removeObjectAtindex: 5];
[someTextField setTextValue: foo];
BOOM!
Your code just crashed. Maybe (it won't crash if foo happens to be a constant string or happens to have been retained by something else or happens to have been retain/autoreleased somewhere else).
Technically, that should be:
NSString *foo = [aMutableArray objectAtIndex: 5];
[foo retain];
[aMutableArray removeObjectAtindex: 5];
[someTextField setTextValue: foo];
[foo release];
That is, foo should be retained the moment it comes into scope and released the moment it is no longer used in a scope. Or you could [[foo retain] autorelease];, but autorelease pressure can be a problem (it generally isn't, but it can be).
ARC does this kind of analysis and would ensure that foo is retained as shown above when necessary.
You do not have to worry about the object being passed going away so there is no need to retain it. Proper memory management* ensures that the object will live for the duration of your method because it will be within the same thread as the caller, therefore the autorelease pool for that thread should not be drained and the caller can not release the object until your method has returned. This even holds true with methods such as performSelectorInBackground because that will retain the argument.
*Proper memory management - This means each thread that uses auto released objects gets it own autorelease pool that is drained within the same context it is created and objects passed across threads are properly retained.

Objects creation and instantiation in objective-c

Given the piece of code below where blueViewController is an iVar.
Question: Why not instantiate the iVar directly?
BlueViewController *blueController = [[BlueViewController alloc]initWithNibName:#"BlueView" bundle:nil];
self.blueViewController = blueController;
[blueController release];
It depends on where you are in your class. If you are in your init (and dealloc) method it is recommended to refer to the ivar directly to avoid any side effects in setter logic. Therefore in the init I would do
_blueViewController = [[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil];
But anywhere else I would do it how you have done it. Then if there is any custom logic in the getter/setter I know it will be run.
To eleborate on #Vladimar's point the synthesized setter for a retain will do some memory management similar to this:
- (void)setMyObject:(MyObject *)newMyObject
{
// If it's the same object we don't need to do anything
if (_myObject != newMyObject) {
[newMyObject retain];
[_myObject release];
_myObject = newMyObject;
}
}
It is much safer to let the getters/setters worry about all this logic any time you set your ivars.
You can initialise iVar directly, but the code you have also handles memory management for the previous blueViewController value. Accessing iVar directly you'll have to release previous value manually before assigning new one.
You can do it all on one line if you want. The important thing is to balance the +alloc with a -release or -autorelease. So, you can say:
self.blueViewController = [[[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil] autorelease];
That's fine, but some folks prefer to avoid -autorelease, and some folks just prefer simpler steps and/or shorter lines of code. Using an intermediate variable as you've done helps in that respect, and it doesn't cost anything.
It depends on whether the property is retain or not. Most object properties are retained; this is what a retain property looks like:
- (void)setBlueViewController:(BlueViewController *)bvc {
if (bvc != blueViewController) { // blueViewController is local ivar
[blueViewController release];
blueViewController = [bvc retain];
}
}
So what you're doing up there is creating a retain count of +2. When you init, that's a +1; the property then retains it, bumping it up to +2. Your dealloc releases it once, which brings it down to +1...and you've leaked that property. Because you are alloc/init-ing the variable, you don't want to use the setter; instead, assign it directly to the instance variable.
By instantiating it directly, it saves you the trouble of that other release—fewer lines of code means fewer errors. You might, for example, have typed retain by accident and not realized it until your program crashes because you retained a massive class...
Of course, as Caleb says you could autorelease, but that's effectively letting the object lie around in memory until the run loop is finished. It's much easier, and gives you more control, to just not worry about that. There's nothing wrong with assigning the alloc/init to the ivar; in fact, that's the best way to do it.

Objective-C Difference between setting nil and releasing

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.