如何最好地为 ARC 代表保留自我?

Posted

技术标签:

【中文标题】如何最好地为 ARC 代表保留自我?【英文标题】:How best to retain self for delegate with ARC? 【发布时间】:2013-08-06 20:54:56 【问题描述】:

想象三个班级。 ClassA 和 ClassB 是我的。第三类是 UIViewController,我不能修改它的代码:

在A类中:

- (void) aMethod

    ClassB *classBInstance = [[[ClassB alloc] init] goWithOptions:options];

ClassBInstance 仅在 aMethod 的生命周期内保留。

在 B 类中:

- (void) goWithOptions

    AUIViewController *avcInstance = [[AUIViewController alloc] init];
    avcInstance.delegate = self;
    [viewController pushViewController:avcInstance animated: YES];    // this returns immediately, but we need self to be retained until the delegate is done with it


- (void) cleanupCalledByDelegate //

    // cleanup

-goWithOptions方法被调用时,avcInstance被被调用者保留,但是传递给delegate的self却没有。这意味着只要-goWithOptions 返回,并且aMethod 完成,那么classBInstance 就会被释放,而avcInstancedelegate 将不再有效。

理想情况下,我想将classBInstance(属于B 类的自己)的所有权绑定到avcInstance;当avcInstance 被释放时,classBInstance 或委托被释放。

或者,我可以在 -cleanupCalledByDelegate 中清理 classBInstance,它在 avcInstance 被释放之前调用。

如何最好地处理这个问题?我宁愿不让ClassB *classBInstance 成为ClassA 的属性,因为那样我就必须让它释放classBInstance,我更愿意在ClassB 中处理它。如果这是最好的解决方案,我会使用块并在 ClassA 中传递一个完成块:


    classBInstance = nil;

-goWithOptions,我会打电话给-cleanupCalledByDelegate。这是处理这个问题的正确方法吗?

【问题讨论】:

arc 的一个缺点是你没有太多的控制权。保留/释放现在与属性相关联。要保留/释放某些内容,您必须添加另一个属性。 @JustinMeiners - 不仅仅是属性。强大的 ivars 也适用于范围和关联。 @TomSwift 对,关键是,它现在绑定到一个命名变量,使得解决这类问题变得更加麻烦。 【参考方案1】:

如果你只是想“将classBInstance(ClassB中的self)的所有权绑定到avcInstance”,可以使用objective-c对象关联:

#import <objc/runtime.h>

objc_setAssociatedObject( avcInstance, "my_association", classBInstance, OBJC_ASSOCIATION_RETAIN );

此外,如果您以后需要更方便地访问 classBInstance,您可以将此关联代码包装到一个类别扩展中,该扩展将 classBInstance 公开为 avcInstance 上的一个属性。

【讨论】:

你可以这样做 (+1),但它闻起来像糟糕的应用程序设计。如果 ClassA 需要与 ClassB 建立比标准弱委托更正式的关系,则应将其建模为更正式的关系并显式管理。 但是ClassB不是需要与picker建立更正式的关系吗? A班只是想让某个班级完成一项任务,不想被如何打扰。 B 类需要将自身与需要委托但不保留委托的 UIViewController 选择器链接。 例如ClassA想要显示一些信息。它不关心它是如何显示的,也不关心显示是否成功。它打了个电话,然后愉快地前行。事实上,ClassA 可能想要进行许多这样的显示调用,并假设 ClassB 将管理队列——这意味着 ClassA 中的单个属性不是答案,我们要么依赖于在堆栈上创建唯一实例,要么创建和用于跟踪 ClassB 实例的数组属性。 由于 ClassB 决定它如何显示信息并且必须处理委托回调等,所以最好让 ClassB 和 UIViewController 处理保留,而不是将该任务暴露给另一个类. 我倾向于同意@bbum 的观点,即它“闻起来像糟糕的设计”,但这是你的决定。如果你只是务实并且可以证明你的模式是合理的,那么它可能没问题。 IMO,如果没有更多的洞察力,就很难做出判断。

以上是关于如何最好地为 ARC 代表保留自我?的主要内容,如果未能解决你的问题,请参考以下文章

用强弱自我打破保留周期

在此块中强烈捕获自我可能会导致保留周期

闭包中的弱自我和后果示例

保留“自我”的坏习惯?

为啥自我实现的 getter 应该保留并自动释放返回的对象?

代表自我概念!