Usually, it is the controller's responsibility to retain itself while it completes a task. If your controller runs a task on a background thread, then it should automatically be retained by the instance of NSThread If data is being fetched over the network using NSURLConnection the controller should be retained as the delegate If you are not doing a task like this, you can use synthetic circular retains to retain the controller while the task is being carried out. This can be done by creating an object, I will call it ObjectRetainer that simply has a strong id property.
When the controller begins its task, it should have a strong ObjectRetainer instance variable that gets set to a new ObjectRetainer that retains the controller. This way, the controller is retaining an ObjectRetainer that is retaining the controller, thus preventing either one from being deallocated When the controller completes its task and has called all necessary delegate methods, it should set the ObjectRetainer instance variable to nil. This will release the ObjectRetainer that in turn will release the controller The ObjectRetainer interface might look something like this: interface ObjectRetainer : NSObject { __strong id object; } @property (nonatomic, strong) __strong id object; @end You should declare an ivar in the controller's header: strong ObjectRetainer _retainer Then, in the controller's start method: (void)start { ... _retainer = ObjectRetainer alloc init; _retainer.
Object = self; } When the controller is done, simply set retainer to nil: (void)performBackgroundTask { .... delegate myControllerDidFinish:self; _retainer = nil; }.
Usually, it is the controller's responsibility to retain itself while it completes a task. If your controller runs a task on a background thread, then it should automatically be retained by the instance of NSThread. If data is being fetched over the network using NSURLConnection, the controller should be retained as the delegate.
If you are not doing a task like this, you can use synthetic circular retains to retain the controller while the task is being carried out. This can be done by creating an object, I will call it ObjectRetainer, that simply has a __strong id property. When the controller begins its task, it should have a __strong ObjectRetainer instance variable that gets set to a new ObjectRetainer that retains the controller.
This way, the controller is retaining an ObjectRetainer that is retaining the controller, thus preventing either one from being deallocated. When the controller completes its task and has called all necessary delegate methods, it should set the ObjectRetainer instance variable to nil. This will release the ObjectRetainer, that in turn will release the controller.
The ObjectRetainer interface might look something like this: @interface ObjectRetainer : NSObject { __strong id object; } @property (nonatomic, strong) __strong id object; @end You should declare an ivar in the controller's header: __strong ObjectRetainer _retainer. Then, in the controller's start method: - (void)start { ... _retainer = ObjectRetainer alloc init; _retainer. Object = self; } When the controller is done, simply set _retainer to nil: - (void)performBackgroundTask { .... delegate myControllerDidFinish:self; _retainer = nil; }.
Nice, this worked perfectly! It's kind of a hack but trivial to implement. I'm sure over time I will change the implementation to use blocks but for now this got things working.
– XJones Oct 23 at 21:59.
Since arrays retain their members, your code would look like this: // start a process in a controller - (void)startProcess { MyController *controller = MyController alloc init; // set the delegate, the delegate is defined as (nonatomic, assign) controller. Delegate = self; controller start; if (pendingControllers == nil) { pendingControllers = NSMutableArray alloc init; } pendingControllers addObject:controller; controller release; } // when the delegate is notified, release the controller - (void)myControllerDidFinish:(MyController):controller { // do something with results pendingControllers removeObject:controller; if (pendingControllers count == 0) { // if ARC is enabled, remove the call to -release. PendingControllers release, pendingControllers = nil; } } This avoids the problem.
Completion blocks are the right answer, and they’re what Apple is using going forward, but this method will work for now.
1 Yeah, I thought of that but seems ugly. I am all for using blocks, this is just a big project and I'm trying to convert to ARC while rewriting as little code as possible. I also thought about adding a completion block to the controller and defining the current delegate handlers in blocks.
– XJones Oct 23 at 21:28 If it seems less ugly to you, you can use an NSMutableSet instead. Either way, you’ll solve the problem of the controller being released. – Jeff Kelley Oct 23 at 21:31 +1 because this would work but the answer from @alex worked better for me.Thanks.
– XJones Oct 23 at 22:01.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.