ViewControllers的NSMutableArray不释放其对象的内存

时间:2012-11-11 05:56:15

标签: ios memory-management nsmutablearray viewcontroller

这与我的其他问题here

基本相关

我正在尝试发布包含viewControllers的NSMutableArray。我这样做:

self.viewControllers = nil;

viewWillDisappear,因为我正在转向另一种观点。但无论我做什么,视图控制器都不会被释放。我也尝试过:

[[scrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

其中scrollview是拥有包含NSMutableArray的视图。

虽然包含NSMutableArray的引用计数为0,但我看到实时视图控制器(在乐器中)的数量没有变化。

3 个答案:

答案 0 :(得分:2)

有几点意见:

  1. 确保通过静态分析器运行非ARC代码。这可以找到许多困扰非ARC代码的内存管理问题。从Xcode的“产品”菜单中选择“分析”,或按命令 + shift + B 。如果您使用ARC,很多这些内存管理问题都会消失,但如果您不使用ARC,静态分析器在检查代码时非常有用。

  2. 您对removeFromSuperview的尝试是不必要的,并且不会影响视图控制器的retainCount本身。但是,我是否从这种尝试推断出您已经创建了视图控制器,然后将它们的视图添加到滚动视图中?如果是这样,你是否为每个人做了必要的addChildViewController?如果是这样,您确实需要为每个人执行相关的removeFromParentViewController

  3. 视图控制器的正确释放取决于您如何定义和分配viewControllers数组,以及如何填充它。

    但是,例如,我有一个属性:

    @property (nonatomic, retain) NSMutableArray *array;
    

    我用以下代码初始化它(请注意autorelease本身的NSMutableArray(因为我正在使用将为我保留的访问器方法),以及显式{{1 } release个对象):

    Object

    如果我检查了- (void)makeArray { // create an array, using the accessor method (thus why I'm using an autorelease object) self.array = [[[NSMutableArray alloc] init] autorelease]; // just add four random objects to the array. // note, adding them to the array increases their retain count, thus I // release them to bring the retain count back to +1 ... I could have // done that via autorelease, too for (NSInteger i = 1; i < 4; i++) { Object *obj = [[Object alloc] initWithString:[NSString stringWithFormat:@"Test %d", i]]; [self.array addObject:obj]; [obj release]; } } 值,我可以看到所有内容都有retainCount +1,这是合适的:

    retainCount

    当我在以下方法中清除它时,它(以及数组的各个对象)被正确释放(事实证明- (void)logArray { // let's examine the retain counts for the objects in the array // should be "1" given there are no other strong references anywhere for (id obj in self.array) NSLog(@"%s %@ (retainCount = %d)", __FUNCTION__, obj, [obj retainCount]); // let's also examine the retain count for the array, itself // this should also be "1" NSLog(@"%s retainCount = %d", __FUNCTION__, [self.array retainCount]); } 类在其Object期间NSLog dealloc方法):

    - (void)clearArray
    {
        // let's use the accessor method to release the array and make sure
        // the pointer is nil
    
        self.array = nil;
    }
    
  4. 这是一种冗长的说法,即self.viewControllers = nil;的语法是一种非常适合释放数组(以及它的成员对象)的方法,假设数组被定义为{ {1}}属性,如上一点所示。但是,如果数组的成员对象没有被释放,那么这些对象显然没有将retain降为零。我会在retainCount之前尝试,不仅记录数组本身的self.viewControllers = nil;,还记录数组中各个对象的retainCount,以确认它们retainCount }设置。

    他们在那时应该都有+1 retainCount(否则还有其他东西保留它们,要么因为它们被过度保留,要么有一些保留周期(又称强参考周期)那些视图控制器或其他东西合法地保留它们(例如,在某些时候你将其中一个视图控制器推到导航器堆栈上,但你还没有将它们弹出))。

  5. 如果你还在泄漏,我会使用乐器来find the leak。顺便说一下,当检查调用树是否泄漏时,我发现它对“反转调用树”和“隐藏系统库”很有用。


  6. <强>更新

    上面,在第4点,我警告保留周期的风险。保留周期的一个示例是视图控制器使用retainCount,并且在释放视图控制器时失败到NSTimerinvalidate计时器。离线与您聊天,听起来这可能就是问题,您尝试release release NSTimerdealloc永远不会调用,因为计时器,本身,保留视图控制器。在释放dealloc之前,您需要为具有计时器的任何视图控制器手动invalidaterelease NSTimer(通过释放对视图控制器的强引用)。 (例如,可能有一个停止计时器的协议,让你的孩子视图控制器符合那个。)

答案 1 :(得分:1)

鉴于提供的详细信息,我们很难诊断出来。但是,您可以通过运行仪器(例如泄漏)自行快速诊断。如果相应配置,它可以:

  • 指出保留周期
  • 记录所有引用计数操作
  • 和/或您可以使用快照分析

一旦掌握了这些工具,隔离此类问题所需的时间(通常)应缩短为几分钟。

答案 2 :(得分:0)

你可以做一个快速测试:

- (void) test
{
    NSMutableArray *testArray = [NSMutableArray arrayWithCapacity:0];
    // MyViewController is your view controller class
    MyViewController *vc = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil]; // add autorelease if you aren't using ARC
    [testArray addObject:vc];

    // On exit, testArray will be released, so will vc
}

在MyViewController中的dealloc上设置断点并检查它是否被调用。如果它被调用,而不是在你的代码中,则意味着你的视图控制器被保留在某个地方,你必须找到它们保留的位置。