在调用 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
在我的非 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