【问题标题】:In ARC how does a child object tells parent object I am done, please release me (to avoid memory leaks)在 ARC 中,子对象如何告诉父对象我完成了,请释放我(以避免内存泄漏)
【发布时间】:2017-03-03 06:28:54
【问题描述】:

我的父对象创建一个子对象来执行一些异步操作。它涉及一些用户交互,这也是我没有使用NSOperation 的原因之一。只有子对象知道它什么时候完成了它的任务,那么它如何告诉它的父对象我已经完成了,请释放我以避免内存泄漏?

目前想出这个,父对象有个回调方法叫releaseChild,也就是child = nil;当子对象完成其任务时,它调用父对象的releaseChild 只是为了将自己设置为nil。实际上,我将调用包装在 dispatch_after 中,但想法是一样的,子对象调用其父对象将自己设置为 nil。

我想知道有没有更好的方法?

-----更新-----

我知道写我孩子的“正常”方式是创建一个UIViewController 对象,将其推送到UINavigationController。完成后用户可以弹出它,ARC 将释放它。这样,我不需要担心内存泄漏(通常)。但我认为当子对象完成时释放子对象的问题,只有它知道它何时完成有一个边框应用程序而不是写一个UIViewController 对象。

【问题讨论】:

  • 请问是什么类型的子类???
  • 只是一个带有 UI 和网络内容的“普通”可可对象
  • 因此,您需要覆盖child 中的dealloc() 方法,并使用parent 中的child 对象调用该方法,然后在release 中做任何您想做的事情。
  • 伙计,你不明白我的问题。不要只是为了回答而回答
  • 是的,我已经正确阅读了您的问题,在这里我不仅仅是为了回答,而是为了帮助开发人员,您是否尝试过上述提供的解决方案?不试怎么能说这不是你的问题?

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


【解决方案1】:

在问题中:

只有子对象知道它什么时候完成了它的任务,那么它如何告诉它的父对象我已经完成了,请释放我以避免内存泄漏?

在后面的评论中:

问题是子对象不能将自己设置为 nil。

看起来你需要的是一个控制自己生命周期的子对象。这很容易做到;只要一个对象的引用存储在一个变量中,它就保持活动状态,该变量被认为是对存储在其中的引用的强所有权——并且该属性是变量声明的默认值。那个变量可以是全局的、局部的、实例的,没关系……所以要控制自己的命运,对象只需要保持对自身的引用即可。

以下代码,从Manual object lifetime with ARC 复制而来(我几年前写的一个先前的答案,我可以自己模仿 ;-)),显示了一种方法:

@implementation MasterOfMyOwnDestiny
{
   MasterOfMyOwnDestiny *alsoMe;
}

- (void) lifeIsGood
{
    alsoMe = self;
}

- (void) woeIsMe
{
    alsoMe = nil;
}

...

@end

在您的情况下,您可以在其初始化期间让孩子设置alsoMe,因此孩子开始控制自己的生命周期。当孩子决定它已经完成它的工作时,它只是调用[self woeIsMe] 作为它的final动作。

注意:您当然可以删除方法并直接在子对象中设置实例变量,这样任何其他对象都很难杀死子对象。

如果父级出于任何原因需要对子级的引用,而不是让子级保持活动状态,那么它可以将该引用存储在一个变量中,该变量归因于断言存储在其中的引用的弱所有权,例如类似:

__weak MasterOfMyOwnDestiny *myChild = [MasterOfMyOwnDestiny new];

这样的引用不会使myChild 引用的对象保持活动状态,并且会在该对象死亡时自动设置为nil

【讨论】:

  • 告诉我一些我不知道的事情。谢谢!我将您的答案标记为已接受的答案,尽管@nasher729 答案也有效。 :D
【解决方案2】:

几种可能的解决方案

1)使用协议委托方法让孩子告诉父母它已经完成(我假设这就是你正在做的)

2)您可以将变量传递给孩子,一旦孩子完成执行,它就会被孩子设置,父母可以定期检查它的值并清除孩子(不是一个大粉丝,而是一种轮询方法),可以用创建后台任务或可以添加到低优先级队列。

3) 使用 NSNotificationCenter 向父母发送通知并告诉他工作完成。您可以添加用户信息来识别彼此之间的孩子。

4) 如果你在工作完成后不需要做任何特定的事情,只需使用 dispatch_async 并且不要持有引用,它会完成它的任务并最终消亡

我需要更多详细信息才能向您推荐任何具体方法。如果可能的话粘贴你的代码:)

【讨论】:

  • +1 for 1) & 4), 3) 有效,但不适合,因为通知是未寻址的信息流(广播),但父对象是专用对象。 2)……不,……真的,不。
  • @Amin Negm-Awad,问题是子对象不能将自己设置为 nil。它必须让其他人(例如它的父母)这样做。所以我看不出使用 dispatch_async 是如何做到的。除了答案,在某种程度上只是重复我所说的。我没有看到任何新东西。我绝对不会使用 2/3(不,也不广播)
  • 解决方案1)(委托)让你通知父母,这样他就可以设置他的ivar。解决方案4)是正确的:在你的Q中你说问题是将孩子的引用设置为nil。所以没有别的事可做。在这种情况下,您根本不需要子参考。只需将其删除。该块将孩子保持在其封闭中。当然这不起作用,如果您出于其他原因需要参考(取消?)
  • 也许解决方案 1) 更清楚:简单地使用“回调”而不是适当的委派会引入从子级到父级的依赖关系。使用协议进行适当的委托会消除对父级的依赖。
  • 对于第 4 种解决方案,我仍然不明白。为什么要在其父母中调用 dispatch_async {child = nil} ?我的 releaseChild 方法有什么意义和区别?
【解决方案3】:

如果子对象执行异步操作,它很可能有一个回调块,在操作完成时调用它,无论成功或失败。并且很可能父对象已经创建了子对象,存储了一个引用,告诉子对象开始异步操作,并给它回调块。因此,该回调将是设置对 nil 的一些引用的理想场所。

【讨论】:

  • 嗨,您的解决方案和@CRD 的工作,但我会将他的答案标记为已接受的答案,因为他告诉我一些我以前不知道的事情。对不起:$
猜你喜欢
  • 1970-01-01
  • 2014-08-26
  • 2023-03-23
  • 2010-12-04
  • 2018-07-15
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 2011-03-27
相关资源
最近更新 更多