在我的非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下是否有首选/推荐的方式来实现此模式?
答案 0 :(得分:0)
您的第一个解决方案,保持自我引用,工作正常 - 请参阅Manual object lifetime with ARC。
如果您不能或不希望修改类来管理自己的生命周期,那么标准解决方案是使用关联对象。这是一个标准的运行时功能,它有效地允许一个对象的生命周期与另一个对象的生命周期相关联。在您的情况下,您可以将您的代理与UIAlertView
相关联,从而有效地使代表参考强而不是弱。关于SO的许多问题涉及相关对象,例如参见Is it ever OK to have a 'strong' reference to a delegate?。
HTH