0

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?

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281

1 Answers1

0

Your first solution, keeping a self reference, works fine - see for example Manual object lifetime with ARC.

If you cannot, or do not wish to, modify the class to manage its own lifetime then a standard solution is to use associated objects. This is a standard runtime feature which effectively allows the lifetime of one object to be linked to that of another. In your case you can associate your delegate to your UIAlertView, effectively making the delegate reference strong rather than weak. Many questions on SO deal with associated objects, for example see Is it ever OK to have a 'strong' reference to a delegate?.

HTH

Community
  • 1
  • 1
CRD
  • 52,522
  • 5
  • 70
  • 86