for 循环中的强类对象未保留在 ARC 中

Posted

技术标签:

【中文标题】for 循环中的强类对象未保留在 ARC 中【英文标题】:Strong Class Objects inside for loop is not retaining in ARC 【发布时间】:2015-04-14 17:43:03 【问题描述】:

我有一个手动引用计数项目,其中很少有类通过删除保留、释放和设置编译器标志“-fobjc-arc”转换为 ARC 它们是 2 个启用 ARC(-fobjc-arc) 的视图控制器类,ClassA 和 ClassB。

我在for循环中在ClassA中分配和初始化ClassB的对象以实现一些功能,代码sn-p如下,

@interface ClassA ()

@property (strong, nonatomic) ClassB *classBObj;

@end


@implementation ClassA

- (void)createClassBView 
    for (int count = 0; count <= [dataObject count]; count++) //if count is more than 1 it is not retaining the previous classBObj
    
        classBObj = [[ClassB alloc] init]; //ARC is keeping only 1 object reference of this class but I need to retain all the iterated objects
        [self.scrollView addSubView:classBObj withFrame:myFrame];//only 1 view is getting added as subview even if control comes here more than once
    


@end

以上代码在非 ARC(MRC) 中对我来说可以正常工作,但在启用 ARC 时无法正常工作。再强也不保留ClassB对象,

只有 1 个对象,即;最后一次迭代的 ClassB 对象引用是活动的,其余的正在被破坏并且它正在抛出异常“ClassB 引用到一个已释放的实例”

我尝试在循环内使用if(!classBObj)classBObj = [[ClassB alloc] init];,那时我没有获得对已释放实例异常的 ClassB 引用,但只有一个 ClassB 的子视图被添加到我的滚动视图中(即最后一次迭代)。

请指导我。 提前感谢任何帮助。

【问题讨论】:

您是否缺少selfself.classBObj = ...-addSubView:withFrame: 方法的内部是什么? 【参考方案1】:

您的代码完全按照您的要求执行。您在循环中一遍又一遍地为 ClassB 实例设置相同的引用 self.classBObj。每次循环时,先前分配给self.classBObj 的现有ClassB 实例都需要“让开”,以便可以将新的ClassB 实例分配给self.classBObj。因此,当它被新的替换时,它被正确地发布了 - 正确,因为现在没有对它的现有引用。

事实是,在 ARC 之前,您在这里完全没有管理内存,而采用 ARC 揭示了这一事实。你很幸运你的代码曾经工作过(或似乎工作过)。如果你想维护多个 ClassB 实例,你需要你的实例变量是它们的 array,而不是 single 一个。

(另一方面,如果classBObj 是一个 UIView 并且要作为子视图立即添加到界面中,那么这种情况仍在发生,因此很难看出您的抱怨是什么。确实,奇怪的部分是为什么你一开始就需要 classBObj 作为一个属性;为什么它不只是一个局部变量?不像你需要这些引用被保留在别处,因为你这些引用——作为self.scrollView 的子视图。但是如果您需要这些引用用于以后的目的,并且如果您不想通过使用它们是滚动视图的子视图这一事实来获取它们,那么显然你需要一个数组,正如我刚才所说的。)

【讨论】:

如果在最后一行作为子视图正确添加到滚动视图中,则不应释放。 @iMartin 当然应该发布。它不应该被销毁。这是两个完全不同的东西。仅当保留计数达到零时才会发生破坏。 (但我当然同意我们不知道滚动视图发生了什么;这就是为什么我的第三段是一个括号,因为据我所知,它们实际上并没有被添加到滚动视图,尽管它们应该是。我的主要答案仅限于 OP 询问的问题,即内存管理。) 他说以前的实例正在被破坏,如果它们被添加到滚动视图中,这将没有意义。最有可能的是,如果只有最近的实例继续存在,那么 self.scrollView 必须是 nil,并且唯一保留最近实例的是属性。 @matt 感谢您定义明确的答案,这对我真的很有帮助,是的,我确实想维护多个 ClassB 实例,我需要在 for 循环之外启动一个可变数组并添加实例变量(classBObj) 对象,在每次迭代时进入这个数组?你是这个意思吗?还是你在说别的?谢谢, @Splendor_ios 这当然是一个合理的方法。但是,正如其他人所指出的那样,正如我在回答中所暗示的那样,您还必须问自己您的 addSubView:withFrame: 是否按预期工作。

以上是关于for 循环中的强类对象未保留在 ARC 中的主要内容,如果未能解决你的问题,请参考以下文章

连接 C 与背景中的 ARC 津津乐道对象

什么会导致块在 ARC 下不保留引用的 Objective-C 对象?

容易导致循环引用的场景的解决方案

移除对象时内存未释放 - 不清楚在 ARC 中释放的正确方法

使用 ARC 查找对象的保留位置

ARC 会在啥条件下保留该对象?