在调用 final 方法之前,委托一直处于活动状态,但在 ARC 下

Delegate that's alive until the final method is invoked, but under ARC

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

这里的想法是,代理对象将保持活动状态,直到用户点击按钮,此时代理将调用其宿主的方法并自杀。我对操作 sheet 和连接使用类似的模式。

这不会转换为 ARC。 UIAlertView 上的委托很弱。只有对它的弱引用,AlertCallback 会立即被释放。

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

是否有 preferred/recommended 在 ARC 下实现此模式的方法?

您的第一个解决方案,保持自我引用,工作正常 - 例如参见 [​​=11=]。

如果您不能或不想修改 class 来管理其自身的生命周期,那么标准解决方案是使用 关联对象 。这是一个标准的运行时特性,它有效地允许一个对象的生命周期链接到另一个对象的生命周期。在你的情况下,你可以将你的委托关联到你的 UIAlertView,有效地使委托引用强而不是弱。许多关于 SO 的问题都涉及关联对象,例如参见 [​​=12=].

HTH