2

这基本上与我的其他问题有关

我正在尝试发布NSMutableArray包含 viewControllers 的内容。我愿意:

self.viewControllers = nil;

因为viewWillDisappear我要转移到另一个视图。但无论我做什么,视图控制器都不会被释放。我也试过:

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

其中 scrollview 是拥有包含NSMutableArray.

尽管包含的引用计数NSMutableArray为 0,但我看到实时视图控制器(在仪器中)的计数没有改变。

4

3 回答 3

2

几点观察:

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

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

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

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

    @property (nonatomic, retain) NSMutableArray *array;
    

    我用下面的代码初始化了它(注意autoreleaseNSMutableArray本身(因为我使用了为我保留它的访问器方法),以及对象的显式releaseObject

    - (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值,我可以看到一切都有一个retainCount+1,这是适当的:

    - (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]);
    }
    

    当我在以下方法中清除它时,它(以及数组的各个对象)被正确释放(这一事实通过ObjectNSLog在其dealloc方法期间执行 a 的事实得到验证):

    - (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;是释放数组(及其成员对象)的完美方式,假设数组被定义为retain如前一点所示的属性。但是,如果数组的成员对象没有被释放,那么这些对象显然不会retainCount降为零。我会尝试,就在您之前self.viewControllers = nil;,不仅记录retainCount数组本身的 ,还记录数组retainCount中各个对象的 ,以确认它们的retainCount设置。

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

  5. 如果您仍然泄漏,我会使用 Instruments 来查找泄漏。顺便说一句,当检查调用树是否有泄漏时,我发现“反转调用树”和“隐藏系统库”很有用。


更新:

在上面的第 4 点中,我警告了保留周期的风险。保留周期的一个示例是视图控制器使用 a以及在释放视图控制器时NSTimer失败invalidate和计时器。release与您离线聊天,这听起来可能是问题所在,您试图在其中进行release,但永远不会调用,因为计时器本身正在保留视图控制器。在释放. _ _ (例如,可能有一个停止计时器的协议,让您的子视图控制器符合该协议。)NSTimerdeallocdeallocinvalidatereleaseNSTimerNSMutableArray

于 2012-11-11T07:14:38.530 回答
1

鉴于提供的详细信息,我们将很难诊断。但是,您可以通过运行 Instruments(例如 Leaks)自行快速诊断。如果进行了相应配置,它可以:

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

一旦掌握了这些工具的窍门,隔离这些问题所需的时间(通常)应该减少到几分钟。

于 2012-11-11T06:51:19.933 回答
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 上设置断点并检查它是否被调用。如果它被调用,而不是在你的代码中,这意味着你的视图控制器被保留在某个地方,你必须找到它们被保留在哪里。

于 2012-11-11T10:10:26.830 回答