在调用最终方法之前委托它存活,但在ARC下

时间:2015-09-18 23:51:09

标签: ios objective-c automatic-ref-counting

在我的非ARC iOS代码中,我使用以下模式:委托代理类将单个委托消息转发给其他类,然后释放self。这是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];

这里的想法是代理对象将保持活着,直到用户点击一个按钮,此时代理将调用其主机的方法并自杀。我在动作表和连接中使用了类似的模式。

这不会转化为ARC。 UIAlertView上的代表很弱。只有一个弱的参考,AlertCallback立即释放。

我可以看到几种方法来克服这个问题。回调可以包含对self的引用(故意的ref循环),并在委托消息到来时为nil。也可以从UIAlertView派生一个类,实现委托协议,并使它指定self作为委托 - 但是覆盖init方法会很棘手;我不知道如何覆盖一个可变方法,将未知数量的参数传递给超类。最后,我可以在UIAlertView之上构建一个类别,将self指定为委托,并使用objc_setAssociatedObject作为额外的数据项。笨重,但它可能会奏效。

在ARC下是否有首选/推荐的方式来实现此模式?

1 个答案:

答案 0 :(得分:0)

您的第一个解决方案,保持自我引用,工作正常 - 请参阅Manual object lifetime with ARC

如果您不能或不希望修改类来管理自己的生命周期,那么标准解决方案是使用关联对象。这是一个标准的运行时功能,它有效地允许一个对象的生命周期与另一个对象的生命周期相关联。在您的情况下,您可以将您的代理与UIAlertView相关联,从而有效地使代表参考强而不是弱。关于SO的许多问题涉及相关对象,例如参见Is it ever OK to have a 'strong' reference to a delegate?

HTH