【问题标题】:Can't release array objects, but they are causing leaks无法释放数组对象,但它们会导致泄漏
【发布时间】:2011-03-17 21:31:07
【问题描述】:

我有 2 个数组,1 个在 viewDidLoad 方法中,1 个在 add 方法中(将对象添加到收藏夹)

NSUserDefaults *myDefault = [NSUserDefaults standardUserDefaults];
    NSArray *prefs = [myDefault arrayForKey:@"addedPrefs"]; 
    userAdded = [[NSMutableArray alloc] initWithArray:prefs];

Instruments 显示来自这些首选项 NSArrays 的泄漏。 (上面只显示了一个,其他在ViewDidLoad中完全一样)当我尝试释放它们时,应用程序崩溃并且它们是在本地定义的,所以我无法在dealloc方法中释放它们。

是否可以将我的 userAdded NSMutable 数组直接分配给 arrayForKey?还是会导致不匹配?

如何阻止这种泄漏?

【问题讨论】:

    标签: iphone objective-c memory-management memory-leaks instruments


    【解决方案1】:

    文档没有指定是否 initWithArray: 将旧数组(prefs)中的对象添加到新数组(userAdded)时额外保留。它应该,因为这些项目正在被添加到新数组中。也许当旧数组(首选项)被释放时,userAdded 中元素的保留计数下降得太低,对象也被释放,应用程序崩溃。为了检查这一点,我在调用 initWithArray: 之前和之后询问了第一个数组的内容的保留计数。

    NSUserDefaults *myDefault = [NSUserDefaults standardUserDefaults];
    NSArray *prefs = [myDefault arrayForKey:@"addedPrefs"]; 
    NSUInteger i, count = [prefs count];
    for (i = 0; i < count; i++) {
        NSObject * obj = [prefs objectAtIndex:i];
        NSLog(@"Object: %@, Retain count: %d.", obj, [obj retainCount]);
    }
    userAdded = [[NSMutableArray alloc] initWithArray:prefs];
    for (i = 0; i < count; i++) {
        NSObject * obj = [prefs objectAtIndex:i];
        NSLog(@"Object: %@, Retain count: %d.", obj, [obj retainCount]);
    }
    

    对象报告保留计数增加,因此可以释放 prefs 数组而不影响新数组。但是运行这段代码仍然会泄漏一个 NSArray。

    所以问题一定出在 prefs 数组上。由于 NSUserDelfaults 方法 arrayForKey: 产生了 prefs 数组,但在此方法的名称中没有找到“alloc”、“new”或“copy”等词,调用方法不拥有 prefs 数组。最有可能的是,prefs 数组已添加到自动释放池中。为了测试这个想法,我在上面的测试代码中调用了NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];[pool drain]。运行此代码不会泄漏数组。

    所以我认为 prefs 数组被添加到一个不会被耗尽的自动释放池中。消除这种泄漏的最简单方法是在创建 prefs 数组之前创建一个自动释放池,并在使用 prefs 数组时清空该池。

    【讨论】:

    • 我们不知道initWithArray: 的内部工作原理,它还不如retain 给定的NSArray,所以试图理解保留计数是有危险的。 (我想:为什么不呢,因为NSArray 是不可变的?它可以跟踪对NSArray 的更改,或者只在写入时制作它自己的副本或类似的东西。)
    • “文档没有指定是否 initWithArray: 将旧数组(首选项)中的对象添加到新数组时额外保留”是的。数组总是保留它们的元素 - 或者做一些事情来阻止它们被释放..
    • 现在我很困惑。我应该使用上述问题中描述的最后一种方法吗? userAdded = [[NSMutableArray alloc] 等 copyItems:YES];
    • 我所有的泄漏都来自我 initWithArray someNSUserdefaultsArray 的各个地方。我原以为 initWithArray 会用对象填充数组,但我猜如果有 copyItems 调用就不会。所以我应该只是 copyItems:YES 然后释放 NSUserdefaults 数组?
    • 上面的 sn-p 仍然会泄漏一个 NSMutableArray,它已分配但从未释放。请参阅下面的答案。
    【解决方案2】:

    释放用户添加于-dealloc

    【讨论】:

      【解决方案3】:

      泄漏是你alloc 没有release。每个alloc(或copy)都应该在某个地方后面跟着releaseautorelease(但不要太早——这可能导致你的崩溃?)

      如果您需要在函数范围之外保留userAdded,请将其设为保留属性并分配给self.userAdded

      那就去吧

      self.userAdded = [[[NSMutableArray alloc] initWithArray:prefs] autorelease];
      

      并且有一个

      @property (nonatomic,retain) NSMutableArray * userAdded;
      

      还有一个

      @synthesize userAdded;
      

      堵塞泄漏。

      【讨论】:

      • 谢谢。除了自动释放,我这样做,但 Instruments 说它是一个正在泄漏的 NSArray。 NSArray 是来自 NSUserdefaults 的首选项数组。如果我在方法结束时释放此首选项,应用程序崩溃?
      • 这是正确的 - 如果你释放 prefs,你会崩溃。 prefs 来自“工厂”方法(即不是具有 alloc/init 的方法),因此它是预先自动释放的,并且在该块超出范围时将被释放。所以,如果它在那里崩溃 - 好!那就是你想要的!但是,如果“prefs”泄漏,它可能在代码中的其他地方有保留计数。你能用 Instruments 显示对象分配的完整历史吗?
      • NSArray 可能会被NSMutableArray 保留(请参阅我对另一个问题的评论),因此如果您没有正确释放NSMutableArray,它仍然会泄漏。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-25
      • 1970-01-01
      • 2011-06-16
      • 2010-11-25
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      相关资源
      最近更新 更多