views:

136

answers:

4

I need to call a method that starts some asynchronous code

MyClass* myClass = [[MyClass alloc] init];
[myClass startAsynchronousCode];

Now I cant simply release it as this would cause an error since the code is still running:

[myClass release];  // causes an error

What is the best way to deal with the memory?

+2  A: 

You could have -[MyClass startAsynchronousCode] invoke a callback:

typedef void(*DoneCallback)(void *);

-(void) startAsynchronousCode {
  // Lots of stuff
  if (finishedCallback) {
    finishedCallback(self);
  }
}

and then instantiate a MyClass like this:

MyClass *myClass = [[MyClass alloc] initWith: myCallback];

myCallback might look like this:

void myCallback(void *userInfo) {
  MyClass *thing = (MyClass *)userInfo;
  // Do stuff
  [thing release];
}
Frank Shearar
When 'myCallback' method finishes wont the execution of the code return to the end of the method that called the callback: 'startAsynchronousCode' which has just been relesed?
Robert
Yes, which is why it's important that you really are done before invoking the callback. You won't get any access violations unless you refer to self after the callback.
Frank Shearar
I think you're asking "how is startAsynchronousCode asynchronous?" in your comment? The above idiom is meant for when you create a thread and run startAsynchronousCode from within that new thread.
Frank Shearar
A: 

What I've always done is maintained an instance variable that points to the asynchronous object.

- (id)init {
    myClass = [[MyClass alloc] init];
    [myClass startAsynchronousCode];
}

- (void)myClassDidFinish:(MyClass *)myClass {
    [myClass release];
}
kubi
+1  A: 

You must retain your myClass object internally in startAsynchronousCode method. And release it internally too after it finished.

This behavior used in NSURLConnection, UIAlertView and other async objects.

Skie
+2  A: 

How are you invoking the asynchronous code? If you use NSThread +detachNewThreadSelector:toTarget:withObject:, you'll find that the target object is retained by the thread until it terminates and then it is released. So you can release the object immediately after the asynchronous message.

e.g.

@implementation MyClass

-(void) startAsynchronousCode
{
    [NSThread detachNewThreadSelector: @selector(threadMain:) toTarget: self withObject: nil];
}

-(void) threadMain: (id) anObject
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    // do stuff
    [pool drain];
}
@end

With the above, the following code is perfectly safe:

MyClass* myClass = [[MyClass alloc] init];
[myClass startAsynchronousCode];
[myClass release];
JeremyP