 |
 |
Convenience methods - confusing!
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Nov 2002
Status:
Offline
|
|
I'm working through some huge memory leaks in an app I'm writing, and by this point I've made sure that everything I've specifically [alloc]'ed is being released. Now it comes to all the other little objects that move into and out of the life of my program, all of which are generated or returned by a convenience method. Is there any single standard for knowing whether such objects should be retained, autoreleased, or released outright when I am done? Is there anywhere i can find out the reference count I should expect on an object passed by certain convenience methods? Will the pain ever stop!?!???
|
|
I offer strictly b2b web-based server-side enterprise solutions for growing e-business trusted content providers ;]
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Feb 2001
Location: Vancouver, WA
Status:
Offline
|
|
Convenience methods (+stringWithFormat:, +arrayWithCapacity:, etc.) always return autoreleased objects. You don't have to release them yourself, but you do need to retain them if you expect them to be around later.
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
Every 'alloc' 'retain' 'copy' or 'mutableCopy' should have a corresponding, guaranteed-to-be-called "release" or "autorelease". Every "malloc" and "calloc" should have a corresponding "free". Every "new" should have a corresponding "delete".
That's about it...
Also, you can #import <NSDebug.h> to help track down memory leaks. Oh, and MallocDebug (in /Developer/Applications) is pretty awesome, too.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Oct 2001
Location: London
Status:
Offline
|
|
The thing about convenience constructors is that their method names start with the name of the object that will be returned.
That makes them easier to spot (if you aren't sure) - e.g. [NSString stringWithString], [NSArray arrayWithCapacity], etc..
If you want to keep the returned object "alive" outside of the block you are in you should retain it.
And as Smeger said - release anything you retain or copy or init yourself.
e.g. you wouldn't need to retain the following:
Code:
{
NSString *fooString;
fooString=[NSString stringWithString: "Foo Moo, Blue" ];
NSLog(@"foo: %@", foo);
}
Because it does not get released until the end of the {} block.
However - Here, you would retain:
Code:
NSString *fooString;
if (1==1)
{
fooString=[[NSString stringWithString: "Foo Moo, blue" ] retain];
}
NSLog(@"retained foo: %@", foo);
[foo release];
because foo is autoreleased by the conv. constructor. (and has been released by the time the "retained Foo" NSLog happens)
Does that make sense?
(Last edited by Diggory Laycock; Feb 6, 2003 at 06:17 AM.
)
|
|
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Nov 2000
Status:
Offline
|
|
I thought an autoreleased object was guaranteed to be valid until the method it was autoreleased in was complete. Why are you retaining in your second example? Is it only guaranteed to be valid for the current block?
|
|
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Nov 2000
Status:
Offline
|
|
Forgot about this case
Code:
-(void) foo
{
NSAutoreleasePool *pool;
NSString *string;
int count;
for(count = 0; count < 10; ++count) {
pool = [[NSAutoreleasePool alloc] init];
string = [NSString stringWithString:@"Hello"];
// Do lots of stuf w/ string
[pool release];
}
// string is invalid here.
}
Obviously the valid until end of current method statement doesn't hold here. Apple covers all of this pretty well here.
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Oct 2001
Location: London
Status:
Offline
|
|
Originally posted by int69h:
I thought an autoreleased object was guaranteed to be valid until the method it was autoreleased in was complete. Why are you retaining in your second example? Is it only guaranteed to be valid for the current block?
yes - it seems I don't know as much as I thought I did!
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
Originally posted by Diggory Laycock:
However - Here, you would retain:
Code:
NSString *fooString;
if (1==1)
{
fooString=[[NSString stringWithString: "Foo Moo, blue" ] retain];
}
NSLog(@"retained foo: %@", foo);
[foo release];
because foo is autoreleased by the conv. constructor. (and has been released by the time the "retained Foo" NSLog happens)
Does that make sense?
This is not correct. If we were talking about C++ objects, you'd be nearly right. In C++, stack variables are destructed when they go out of scope. So, if we were talking C++ instead of objective-C and the code was:
Code:
#include <stringstream>
char* fooString;
if (1==1)
{
stringstream tempString("Foo Moo, blue");
fooString = tempString.str().c_str();
}
cout << fooString << endl;
you'd probably seg-fault when you got to the 'cout' line because tempString was destructed as soon as it went out of scope, taking the buffer for fooString's along with it. (btw, this example wouldn't work either because c_str() returns a const char*, not a char*. But it gets the point across.).
Okay, back to objective-C, which is what people care about. If you've got an autoreleased object with a retainCount of one, it gets deallocated whenever it's NSAutorelease pool does. Here's the scenario under "normal operating conditions":
[list=1][*]The user presses a key that will eventually cause some autoreleased object to be created.[*]The OS sends the keystroke to your application's runloop, which had been sitting around waiting for an event, using 0% CPU.[*]Your app's runloop creates an NSAutorelease pool.[*]The NSResponder class eventually propagates the keystroke to your class.[*]Your class contains the code "NSArray *myArray = [[NSArray alloc] init];". This creates a new NSArray object. The object has a retainCount of 1 and is not in an NSAutoreleasePool.[*]You call "[myArray autorelease]". Your NSArray object is placed into the topmost NSAutoreleasePool (the one created when the OS gave the keystroke to your app). It still has a retainCount of 1.[*]Your code (and the NSResponder code that called your code) finishes whatever it's doing, returning execution to your app's runloop.[*]The runloop releases the NSAutoreleasePool it created. Since "myArray" is in the NSAutoreleasePool, it is sent a "release" message. Its retainCount is now zero, so it is deallocated.[*]The runloop waits for another event from the OS, using 0% CPU.[/list=1]
So, your autoreleased object generally lives until "whatever it is that you're doing" is done. Which is a very useful lifespan - not too long and not too short.
Notice also that there's something super-handy about this. If you pepper your code with NSParameterAsserts and one of them fires, you'll exit from every function in the call-chain. You'll exit every method or function that was called until you get to one that has an exception-handler. The runloop has an exception-handler, so the result of this is that if an assertion fires, it will basically cancel the current operation and clean up behind itself. Groovy.
'Kay, this was a long post. I hope it's understandable.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Addicted to MacNN
Join Date: Mar 2000
Location: London, UK
Status:
Offline
|
|
Originally posted by smeger:
So, your autoreleased object generally lives until "whatever it is that you're doing" is done. Which is a very useful lifespan - not too long and not too short.
Just to clarify, autoreleased objects are freed when the current autorelease pool is deallocated. Cocoa does this once per iteration though the event loop, so that's where it's most likely to happen.
Sometimes you will want to allocate and free your own autorelease pools, for example if there isn't one already present (in the a Foundation tool or another thread), or for optimization puposes in some circumstances.
|
|
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|