iPhone memory management: a release after setting self.someProperty = nil - iphone

I am reading the LazyTableImages code that Apple have released and they do something to this effect (in an NSOperation subclass):
- (void)dealloc {
[myProperty release];
[myProperty2 release];
}
- (void)main {
//
// Parse operation undertaken here
//
self.myProperty = nil;
self.myProperty2 = nil;
}
My thinking is that they do this in case dealloc is called before setting properties to nil.
Is my thinking correct here? Are the releases unnecessary, as self.myProperty = nil effectively releases myProperty?
One thing I have noticed in this code is that they don't release all retained objects in dealloc, only some of them, which is really the cause for my confusion.
Cheers

You can't do self.myProperty = nil or even [myProperty release] after dealloc. Know why? Because self doesn't exist any more.
As for your question, it appears that the releases in dealloc are unnecessary, but it's still good practice to clean up your instance variables in your dealloc method.
edit
As Peter points out in the comment, if the -main method is never executed, then having the release statements in -dealloc is necessary; without them, you'd be leaking memory.

Related

Explanation of `self` usage during dealloc?

I'm trying to lock down my understanding of proper memory management within Objective-C.
I've gotten into the habit of explicitly declaring self.myProperty rather than just myProperty because I was encountering occasional scenarios where a property would not be set to the reference that I intended.
Now, I'm reading Apple documentation on releasing IBOutlets, and they say that all outlets should be set to nil during dealloc. So, I put this in place as follows and experienced crashes as a result:
- (void)dealloc {
[self.dataModel close];
[self.dataModel release], self.dataModel = nil;
[super dealloc];
}
So, I tried taking out the "self" references, like so:
- (void)dealloc {
[dataModel close];
[dataModel release], dataModel = nil;
[super dealloc];
}
This second system seems to work as expected. However, it has me a bit confused. Why would self cause a crash in that case, when I thought self was a fairly benign reference more used as a formality than anything else? Also, if self is not appropriate in this case, then I have to ask: when should you include self references, and when should you not?
I have adopted the following after seeing Apple sample code and iphone dev books.
set outlets to nil in 'viewDidUnload' (use SELF accessor)
release them in 'dealloc' (no SELF)
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
self.button = nil
}
- (void)dealloc {
// no SELF
[button release]; // UI objects
[images release]; // model objects
}
[self.dataModel release] will release a reference to dataModel that you don't own. The subsequent self.dataModel = nil is equivalent to calling [self setDataModel:nil], and the setter method will itself release the dataModel, which you've already done.
Simplest thing would be to only do self.dataModel = nil.
As a more general point, self.blah is not just a polite way of accessing a field. It invokes a method, and that may have side effects. The purpose of such side effects should be to make life safer and easier. If you forget that the method is being called, though, then it can lead to confusion, as here.
As a rule, you should structure your property methods to encapsulate tricky stuff like memory management -- the default implementations will do this as long as you've declared the property attributes correctly -- and then leave it to them. Mixing and matching your own memory management and your property methods' memory management will almost always trip you up in the end.

objective-c over-releasing in dealloc

Is mystring over-released?
-(void)dealloc {
[mystring release];
[mystring release];
[super dealloc];
}
I assume this will not based on [nil release] does nothing:
-(void)dealloc {
[mystring release];
mystring = nil;
[mystring release];
[super dealloc];
}
-EDIT-
Let's say I allocate mystring in init and release it in doSomething:
-(id)init {
if (self = [super init]) {
mystring = [[NSString string] retain];
}
return self;
}
-(void)doSomething {
[mystring release]; // for some good reason
// ...etc
}
Now to avoid over-releasing in dealloc based on my example above do I have to explicitly do this in the doSomething method?
-(void)doSomething {
[mystring release];
mystring = nil; // <- is this mandatory to avoid over-releasing in dealloc?
}
The big question is do I have to explicitly set it to nil when I release it somewhere else in the class to avoid over-releasing in dealloc?
So could I do as many releases as I want in dealloc based if I explicitly set to nil in doSomething?
-(void)dealloc {
[mystring release];
[mystring release]; // <- does nothing because mystring explicitly nil?
}
For your first example, the answer is probably!
In general, each object that holds a reference to another object should retain it until they're done, then call release once, however in some highly exotic (and generally poorly written) cases this may not hold. If you retain the object x times, you need to release it x times, and other cases of poor memory management. But best practice, yes, one retain, one release, don't release more than you retain!
There are two risks with over-releasing like this:
The first is if the first release call makes the refcount of mystring equal to 0, it will be dealloc'd, and then you're sending a message to a piece of memory that is no longer a valid object. Objective-C doesn't really like this, and may react in a variety of ways, including CRASHING. Sending messages to nil, kosher, messages to things dealloc'd, not so much.
The second is if the refcount isn't zero, you just released someone else's reference, so at some point in the future, an object that has a reference to mystring may think that reference is valid and it won't be because it was dealloc'd when the refcount hit zero on a subsequent release call. This will be harder to detect than the previous error, where a debugger will at least show you the real area the problem originates from in the stack frame trace.
Your second example is correct - sending a message to nil does nothing. If you fear you'll do things like this, be sure to set your variables to nil after releasing.
EDIT: Yes. That's what you should do if you intend to release in more than one place like that, however depending on the application, you might consider using an auto-release pool.
It all depends on how many time you retained mystring. If you have two members that may refer to the same object and both retain the object, they should both release the object.
So your first example would be correct if you use mystring = [[somestring retain] retain];
The second one will be better. Because when you release, you release the memory the mystring point to not the memory of the mystring. So, the mystring is not null and if somebody accidentally use it, your app will crash. It also depends on how many times your mystring is retained

What's the best way to release objective-c properties?

I'm new to memory-management, and am reading different things about how to best release properties.
If I have:
in .h:
#property(retain) NSString *myStr;
and in .m:
#synthesize myStr = _iVarStr;
Should my dealloc have:
[_iVarStr release];
or
self.myStr = nil;
or something else?
Thanks!
Both self.myStr = nil and [myStr release] ultimately do the same thing.
Calling [myStr release] is obvious and just releases it.
Meanwhile, the setter method for myStr looks roughly like this:
- (void)setMyStr:(NSString *)newMyStr
{
[newMyStr retain];
[myStr release];
myStr = newMyStr;
}
So when we do self.myStr = nil, we're first retaining a nil object, which does nothing. Then we release the old variable, which is what we want. Finally, we set the pointer to nil.
What's the difference? The latter sets the pointer to nil. This is better because if we (accidentally) send a message to the released object, we crash if the pointer isn't nil (EXC_BAD_ACCESS). Now honestly, since you're in -dealloc, the object is being destroyed anyways, so it wouldn't really matter what you use.
When a property is set to retain then
self.ivar = nil;
will properly manage the memory allocation. For other property types check the at the official documentation page. It also has a bunch of sample code so you can understand what happens "under the hood" for all the options.
Your dealloc should be this:
- (void)dealloc {
[_iVarStr release];
[super dealloc];
}
Although setting the property to nil is possible, I worry about unintended side effects or KVO actions triggered by the change that may not realize the object is currently being deallocated.
I recommend you use self.ivar=nil(the code ivar=nil previously I wrote was wrong) way in dealloc method. Because, if the ivar's property change from retain to assign (or from assign to retain), you don't have to change your code.

What is the best way to dealloc memory in Objective C?

I have a query regarding the memory management.
Let's begin with an example. Assume we have a class as follows.
#interface myClass : NSObject {
NSString *xyz;
}
#end
Now, see the implementation.
#interface myClass : NSObject {
NSString *xyz;
}
#end
#implementation myClass
-(void)abc{
// xyz allocted here
}
-(void)pqr{
// retained or copied many times or may not a single time
}
-(void)mno{
// retained or copied many times or may not a single time
}
-(void)jpg{
// may be released more than one time or may be not
}
//-(void)dealloc{
// [xyz release];
// [super dealloc];
//}
//
//-(void)dealloc{
// if(xyz!=nil && [xyz retainCount]>0){ [xyz release]; xyz=nil; }
// [super dealloc];
//}
-(void)dealloc{
if(xyz!=nil){
while([xyz retainCount]>0)
[xyz release];
xyz=nil;
}
[super dealloc];
}
#end
In above code. I have three dealloc functions. Which one is preferable? If none of these, then please suggest yours.
I am confused because Objective C says, object must be released each time = each time alloc/retained.
But most of the sample code has just single statement "[xyz release];" doesn't it create a memory leak?
This is absolutely wrong:
while([xyz retainCount]>0)
[xyz release];
xyz=nil;
retainCount will never return 0, because as soon as you are at a retainCount of 1 and the object is released, the runtime just deallocates it right then and there, never decrementing the retainCount. Even if it did decrement the retainCount, the object is now deallocated. How are you going to ask it what it's retainCount is?
In a nutshell, your design is wrong. If you can't keep track of how often you've retained an object in a smarter way, then you will have memory leaks and most likely crashes from overreleasing objects (this while loop will crash your app).
If you absolutely can't change your code (I wouldn't believe you if you said you couldn't), then you'd want to keep a second integer ivar indicating how many times you've retained xyz, and then use that to figure out how many times you should release it. (However, this should be an absolute last ditch effort, as in Armaggeddon will happen if you don't get this working in 30 seconds. You should really refactor your code first.)
In addition, you've forgotten the call to [super dealloc] in your dealloc method.
- (void)dealloc {
[xyz release];
[super dealloc];
}
...is the correct version. In Objective-C, you generally shouldn't use the retainCount method.
If you want to be very safe, you can also write:
- (void)dealloc {
[xyz release], xyz = nil;
[super dealloc];
}
The idea is that myClass has a member variable (in your case, xyz). When a myClass object gets created, it should create (or get a reference to) xyz by adding only 1 to the retain count (whether through retain or other means depends on the situation).
It would not be a good idea in each method to retain xyz with releasing it again. So at the end of each method, the the local object should have no more holds on xyz than it had at the beginning of the method.
By the time dealloc gets called, only that single retain hold should remain on xyz (as far as the myClass object is concerned), so a single call to release will suffice. It is not a good idea to release until the retainCount is zero because another object somewhere might be using it.
To directly answer your question, use this dealloc:
-(void)dealloc{
[xyz release];
}
objects those are retained during the poperty declaration need to be released in the dealloc method. So if you are declaring
#property(nonatomic, retain)NSString xyz;,
you need it to be released in dealloc as
-(void)dealloc{
[xyz release];
[super dealloc]
}
Any other allocated memory should be released immediately after the last use of that object from within your methods.
So if you are allocating xyz, in
-(void)abc{
// xyz allocted here
}
then you shoud release it at the end of the same method.
-(void)abc{
// xyz allocted here
// do something with xyz
//release xyz
example:
-(void)abc{
xyz=[[NSString alloc]init];//this may not be what you are following, but i just meant allocating memory
// do something with xyz
[xyz release]
//release xyz
In this case you need not release it in the dealloc method.
Also not that if you are property declaring xyz and retining it, you should not allocate it in your methods nor should release
while([xyz retainCount]==0)
[xyz release];
Should be > 0, otherwise the -release is not executed. Even so, deallocating xyz like this is a bad practice because xyz may be still owned by someone else.
You should allocate xyz one and only one time, and if you -copy it to replace xyz, always -release the old one. Always follow the Cocoa memory management rule.
If you really need to adopt multiple ownership to xyz, and a separate integer ivar to record how many times you have retained xyz, so you have the correct number to -release in -dealloc.

Why should I write [anView release], anView = nil; rather than [anView release];?

Somewhere I was reading that - regarding low memory warnings and giving up an non-visible view with all it's subviews (= a whole nib, I think), you should do that:
-(void)dealloc {
[anView release], anView = nil;
[someImageView release], someImageView = nil;
[super dealloc];
}
rather than
-(void)dealloc {
[anView release];
[someImageView release];
[super dealloc];
}
What's the reason for grounding those pointers to nil (= "no object"), after I call release? Let me guess: Some other method could have -retain'ed the view for some reason (anyone any example for when this could happen?), then the didReceiveMemoryWarning thing happens, and you release a whole nib+view that's currently not visible (i.e. in a multiview-app). As soon as the user wants to see that view again, you would quickly load the nib again and then: It loads all views, connects the outlets, and BANG! Your other retain'ed view's are hanging now without any pointer somewhere lonely in the memory brick, causing a fat and deep memory leak until your app crashes.
Right/Wrong?
The principle is more general than UIView. indeed it is more general than Objective-C/Cocoa -release method. It is valid also with C malloc()/free() memory functions.
When you no longer need an object or any memory zone, first you release/free it. Then, to make sure that you won't use it again, you clear the means to access this object or memory zone by assigning a nil to an object or a NULL to a memory pointer.
Some other method could have -retain'ed the view for some reason
Unless you're invoking dealloc yourself, it's only called when the retain count becomes zero.
Note that in Objective-C sending a message to a nil "object" is (often) perfectly fine. Doing so will not make your program halt, but the message is simply ignored. However, you cannot send a message to a freed object, which would yield a crash.
So, the following would give you an error:
[anView release];
[anView doSomething];
But, this is in fact ok:
[anView release];
anView = nil;
[anView doSomething];
It's a matter of taste, but for the above, you might in fact prefer to crash your program, rather than wondering why doSomething is not executed...
See also Sending Messages to nil from Apple's Introduction to The Objective-C 2.0 Programming Language.
The -dealloc method is called when the object is freed and no other methods on the object will be executed after. Therefore, setting any instance variable to nil has no effect outside that object.
If you were releasing an object (without using a setter) somewhere else in the class, it would be important to set the instance variable to nil to prevent code elsewhere from sending a message to that address.
I use this pattern a lot:
- (void) showHelp: (id) sender
{
if (helpController == nil)
{
helpController = [[HelpController alloc] initWithNibName: #"Help" bundle: [NSBundle mainBundle]];
}
[self presentModalViewController: helpController animated: YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
[helpController release];
helpController = nil;
}
Pretty much everywhere that I allocate a viewcontroller that is modal, or otherwise "temporary". This way, it hangs around if I need it again, but goes away if memory gets low.
rather than doing the expicit release and set to nil, if your accessors have properties associated with them yoc and do the following as a more concise method:
- (void) dealloc
{
self.retainedProperty1 = nil;
self.retainedProperty2 = nil;
self.copiedProperty = nil;
self.assignedProperty = nil;
}
this way you can have code that has less repetition since the synthesized code will take care of your releases for you.
Edit: i should point out that your properties can't be readonly or else you get compiler errors for obvious reasons :)