I use the following pattern in my app and am transitioning to ARC. Basically, an object retains an instance of a controller and releases that controller when it is notified through a delegate protocol that it has finished. I don't use an iVar/property b/c startProcess can be called N times to process N things.
Example below:
// 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];
}
// when the delegate is notified, release the controller
- (void)myControllerDidFinish:(MyController):controller
{
// do something with results
[controller release];
}
When the above implementation is converted to ARC, the controller is no longer retained after startProcess
concludes so the processing doesn't occur and the delegate message is never received.
QUESTION: When converting my project to use ARC, how would the above implementation be modified to work correctly w/o creating iVars in the object instantiating the controller? There is a similar example in Apple's documentation to transition to ARC but it involves using blocks. I'd rather not replace the delegate protocol with completion blocks.
EDIT: added comment in code re how delegate is defined
EDIT: clarified first para to explain why an iVar/property to hold the controller won't work
Why not just create an NSMutableArray
instance variable, pendingControllers
, and adding your controller there? 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With