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.
Related
I am newbie to iPhone programming. I have the following doubt which is stopping me to go ahead. Please consider the following code:
---------.h------
#interface myClass: UIViewController
{
UIImage *temp;
}
#property (nonatomic, retain) UIImage *temp;
---------.m------
#interface myClass
#synthesize temp;
-(void) dealloc
{
[temp release];
[super dealloc];
}
The above is the only program code. Thats it ... nothing else. Do I need to declare [temp release] in dealloc method even though I am not using the property accessor method in my program at all. What if I don't declare [temp release] in dealloc. Will that create memory leak as I am releasing something which I haven't retained as I am not calling property accessor method.
Also when i print retain count for temp why does it show 0 even though it is getting retained in #property.
Thanks in advance
If no value has ever been assigned to (an instance of) myClass.temp, then there won't be a leak. But you should release it in your dealloc.
#property is only a declaration that instance of myClass will have this property. You need to assign it a value before that value gets retained.
myClass *instance = [[myClass alloc] init];
// instance will now retain the value passed in
// and is therefore responsible for releasing it
instance.temp = [UIImage imageNamed:#"whatever"];
// if instance is not retained anywhere else,
// its dealloc will be called
[instance release];
On a sidenote, you should give your classes names that start with an uppercase
letter, i.e. MyClass. Not required, but makes things clearer.
You can also use self.temp = nil; in your dealloc You're sorta not supposed but it kinda works better and looks cleaner. It's a bit of an iffy subject...
What you are doing is correct. Scroll to the "dealloc" section of this Apple Doc: Declared Properties
Soon, however, these properties will be cleaned up automatically when you synthesize them (in the next Cocoa update) -- that being said, a convention I have personally began to follow so that my code works in the future is setting self.temp = nil; in dealloc instead of sending a release message (read the apple doc i posted, it explains this). The accessor method created at runtime releases the object first, so for me and quite a few other devs, this is a better/safer way of cleaning up declared properties in our dealloc.
Your code is correct.
The general rule is that, for all variables you declare in #interface, you must clean them up in -dealloc. Some variables will need to be released, others just need to be nil'd out, depending on how you've declared the #property.
In your example above, temp may never have been given a value explicitly by you, but the ObjC runtime will have initialized the value of temp to nil when an instance of your class gets allocated.
Sending a -release to a nil object is generally not a problem, so the [temp release] is fine. It's a no-op. When temp has a non-nil value in -dealloc, the [temp release] gets to do its job of freeing up the memory.
If you need temp to have a non-nil value on creation, you'll need to implement the -init method and make sure it gets some value. While your class is legitimate & functional without an -init method, you really should get in the habit including one in every custom class you design.
You'll need the default initializer at a minimum: -init. You may also want to design a more detailed initializer that could be used to give your temp ivar an a value, like -initWithImage:
Here's what you should also be including in your class:
#implementation MyClass
...
- (id) init {
self = [super init];
if (self != nil) {
// The minimal default initializer.
// temp will already have a value of nil, so you don't need necessarily
// need to do anything more, unless temp needs a real value on initialization.
}
return self;
}
- (void) dealloc {
...
}
#end
To implement a more detailed initializer, which would be known as the designated initializer, you would to something like this:
#implementation MyClass
...
- (id) initWithImage:(UIImage *)newImage {
self = [super init];
if (self != nil) {
temp = [newImage retain];
}
return self;
}
// Implement the default initializer using your more detailed initializer.
- (id) init {
// In this default initializer, every new instance comes with a temp image!
return [self initWithImage:[UIImage imageNamed:#"foobar"]];
}
- (void) dealloc {
...
}
#end
Here, the designated initializer -initWithImage: is the authoritative initializer. All other initializers, including -init, get implemented using -initWithImage:.
You get to exercise a lot of discretion over whether to implement any initializers beyond the minimal default initializer. Maybe -init is good enough for your purposes. That's fine. Sometimes more detailed initializers make using the class more convenient. Experience (and the Force) will be your guide.
Note that I didn't use the generated property accessor in either initializer method. If you aren't required by circumstances, you should generally avoid using property accessors in -init methods and -dealloc, primarily because of potential pain-in-the-ass issues with side effects of automatic key-value coding notifications.
The initializer and dealloc methods play a special role in a class. As the class designer, it is your responsibility to set and clean up instance variables in these methods. A good rule of thumb is to leave the use of synthesized property accessors for the callers of your class, and the implementation of other methods in the class.
When doing initialization of an instance, or deallocation, you can and should touch the ivars directly. They're yours. You declared them, so you can handle them directly. When implementing other methods in your class, you generally should use the property accessors.
JeremyP's link to the Cocoa Conceptual documentation on objects is a good one. You should definitely read the sections on Objects, and periodically re-read it as you gain more experience writing custom classes of your own. Eventually, it will all start making sense.
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.
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
Let's say I'm building a new class for the iPhone in Objective-C. In one of my init methods I want to manually allocate some memory. So, I might have something like this:
- (id)initWithSomeObject:(SomeObject *)someObject {
self = [super init];
if (self != nil) {
myObject = someObject;
[myObject retain];
if ( (memory = calloc(1, sizeof(SomeStruct)) == NULL) {
// What should I do here to clean up
[self release];
self = nil;
}
}
return self;
}
Now, assuming that the calloc() could fail, and that failing to allocate memory is catastrophic for my object, what should I do inside the if-body to clean up properly? Is there an Objective-C idiom or pattern that I should be using?
Edit: I included the code posted by Rob Napier. But, I still have to release myObject, right? Or does the added code somehow trigger dealloc()?
Yes, you should release yourself and then return nil.
[self release];
self = nil;
See Issues with Initializers in the Concepts in Objective-C Programming guide.
You need to clean up anything you need to and then set the self reference to nil. Apple Dev Portal has an article:
Link
I just tried. -dealloc gets called due to [self release], so myObject would not need to get released in initWithSomeObject. To be sure, you might move myObject = [someObject retain]; (I prefer that style in case -retain might fail for some reason) below the call that might fail (if that's possible).
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 :)