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 :)
Related
i am new in ObjC and iPhone.
I downloaded an example of data sharing between multiple views. The basic approach is to create an data model object in the base UIApplication and get/set data from/to it. So in the init method i saw the following code:
- (id) init;
{
self.theAppDataObject = [[ExampleAppDataObject alloc] init];
[theAppDataObject release];
return [super init];
}
And after that, using delegate we can access this object.
id theDelegate = (id) [UIApplication sharedApplication].delegate;
ExampleAppDataObject* theDataObject;
theDataObject = (ExampleAppDataObject*) theDelegate.theAppDataObject;
So, my question is in the first code example. Why do we need to alloc memory for the theAppDataObject object, and immediately after that - release the object? Why don't we get nil when accessing this object later?
10x
I assume theAppDataObject is declared as #property (retain). Therefore, when setting the object by doing self.theAppDataObject (or [self setTheAppDataObject:]), this property will retain the ExampleAppDataObject. Therefore, you can release it afterwards.
When you alloc and init the ExampleAppDataObject, it's retain count goes up to 1. When you set the AppDataObject to this ExampleAppDataObject, it sends retain to it, so the retain count goes up to 2. You can then release your own ownership of the object; it won't get deallocated because theAppDataObject still has ownership.
If that makes sense.
That depends on how theAppDataObject property is defined.
If it provides a retaining setter-accessor the retain count of the appDataObject will flip to 2, one more than needed here.
So release one of it.
Better and more understandable way would be to write
if ( (self = [super init]) ) {
ExampleAppDataObject *myAppDataObject = [[ExampleAppDataObject alloc] init];
self.theAppDataObject = myAppDataObject;
[myAppDataObject release];
}
return self;
Iphone uses reference count based memory management model..See this tutorial first and then apple's technical documentation... theAppDataObject is a property (see the use of self. theAppDataObject) which should be retained for the above code to work..Any object which is retained should have a bonus plus 1 retain count...An object only gets released when its retain count gets to zero..
first things first: that code sample is terrible.
- (id) init
{
// assign self. super may return another address
self = [super init];
// then check for nil
if (self != nil) {
// then assign the ivar directly because you should
// not invoke methods of partially constructed objects
theAppDataObject = [[ExampleAppDataObject alloc] init];
}
// then return the address super returned
return self;
}
now for your questions:
Why do we need to alloc memory for the theAppDataObject object, and immediately after that - release the object?
self.theAppDataObject calls through the setter, which retains, copies, or assigns theAppDataObject. in this case, we could assume it is highly likely to be retained.
Why don't we get nil when accessing this object later?
release does not set a pointer to nil. it sends a message to the object which then decrements the retain count (in the typical case). what you might have expected in this case is an object which has been deallocated. that does not happen when the argument is retained because the reference count does not reach zero in the program you have shown. the object is still alive because it's been retained and the address of the object stored when the setter (self.theAppDataObject = arg) is called.
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.
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.
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).