In my non-ARC iOS code, I use the following pattern: a delegate proxy class that forwards a single delegate message to some other class, then releases self. Here's an example for UIAlertView:
@interface AlertCallback : NSObject
<UIAlertViewDelegate>
{
NSObject *m_Sink;
SEL m_SinkSel;
}
-(id)initWithSink:(id)Sink SinkSel:(SEL)Sel;
@end
@implementation AlertCallback
-(id)initWithSink:(id)Sink SinkSel:(SEL)Sel
{
if(self = [super init])
{
m_Sink = Sink;
m_SinkSel = Sel;
}
return self;
}
- (void)alertView:(UIAlertView *)av didDismissWithButtonIndex:(NSInteger)n
{
//Call the callback
[m_Sink performSelector:m_SinkSel withObject:@(n)];
[self autorelease];
}
@end
//And finally usage:
AlertCallback *del =
[[AlertCallback alloc]
initWithSink:self
SinkSel:@selector(OnIAmSure:)];
UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil
message:@"Are you sure?"
delegate: del
cancelButtonTitle:@"No"
otherButtonTitles: @"Yes", nil];
The idea here is that the proxy object will stay alive until the user taps a button, at which point the proxy will invoke its host's method and commit suicide. I'm using a similar pattern for action sheet and connections.
This doesn't translate to ARC. The delegate on the UIAlertView is weak. With only a weak ref to it, the AlertCallback with be released right away.
I can see several ways to overcome this. The callback can hold a reference to self (a deliberate ref loop) and nil it when the delegate message comes. It's also possible to derive a class from UIAlertView, implement the delegate protocol, and make it designate self as the delegate - but overriding the init method would be tricky; I don't know how to override a variadic method, passing an unknown number of parameters to the superclass. Finally, I could build a category on top of UIAlertView, specifying self as delegate, and use objc_setAssociatedObject
for extra data items. Clunky, but it might work.
Is there a preferred/recommended way to implement this pattern under ARC?