【问题标题】:Why isn't this code leaking?为什么这段代码没有泄露?
【发布时间】:2010-12-05 17:39:35
【问题描述】:

我是开发新手,无法弄清楚:

 for(NSString *collectionName in jsonObjects)
  {
    NSDictionary *collection = [[NSDictionary alloc] init];
    collection = [jsonObjects valueForKey:collectionName];
    NSArray *items = [[NSArray alloc] initWithArray:[collection valueForKey:@"items"]];
    NSNumber *lastAccess = [[NSNumber alloc] init];

    lastAccess = [collection valueForKey:@"lastAccess"];

    [items release];
  }

我不明白为什么,当我释放 lastAccesscollection 时,程序会因 EXC_BAD_ACCESS 错误而崩溃...,但如果我不这样做释放 items 我有泄漏。任何人都可以阐明这一点。我认为如果你使用了 alloc,那么你拥有引用,因此必须释放?

【问题讨论】:

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


    【解决方案1】:

    该代码存在很多问题。暂时忽略基金会缓存某些常用值。

    这种模式没有意义:

    NSDictionary *collection = [[NSDictionary alloc] init];
    collection = [jsonObjects valueForKey:collectionName];
    

    第一行创建了一个 NSDictionary 的(空)实例,第二行立即覆盖了对它的引用。既是泄漏又完全没有意义;不需要在第一行进行分配/分配。稍后lastAccess 也是如此。

    由于第二行返回一个未拥有的引用,因此尝试release 会导致崩溃。

    请注意,如果发生崩溃,则会有回溯。这个问题很简单,不需要它,但总是在回溯中寻找线索。

    请注意,您实际上不会看到 NSNumberNSDictionary 实例的泄漏,因为 Foundation 恰好有这些实例。在 NSNumber 的情况下,它只是没有意义。但是,空字典经常使用,并且使用单例可以节省内存。

    【讨论】:

    • 感谢您回复我 bbum,我不太确定单例是什么,但我会查看文档 :)
    【解决方案2】:
    for(NSString *collectionName in jsonObjects)
    {
      NSDictionary *collection = [[NSDictionary alloc] init]; // Allocation 
      collection = [jsonObjects valueForKey:collectionName]; // overwriting above, LEAKS
      NSArray *items = [[NSArray alloc] initWithArray:[collection valueForKey:@"items"]]; // Allocation
      NSNumber *lastAccess = [[NSNumber alloc] init]; // Allocation
      lastAccess = [collection valueForKey:@"lastAccess"]; // overwriting above, LEAKs
      [items release];
    }
    

    不包含“alloc”或“new”的调用返回对“autoreleased”对象的引用,这意味着它们不归你所有,释放它们会导致崩溃。您可以使用它们,但只能在您所在的功能范围内使用,如果您需要它们以供以后使用,则需要在它们上调用 retain。所以在调用访问器函数时,你只需要声明你需要的变量,而不需要创建新的对象。

    alloc 创建一个新对象,在collection 的情况下,您正在创建一个空的NSDictionary,但是您会立即使用从valueForKey: 获得的自动释放引用覆盖对该新对象的引用,这将创建泄漏。因为最初创建的对象不会被释放。

    应该是这个样子

    for(NSString *collectionName in jsonObjects)
    {
      NSDictionary *collection = [jsonObjects valueForKey:collectionName];
      NSArray *items = [collection valueForKey:@"items"];
      NSNumber *lastAccess = [collection valueForKey:@"lastAccess"];
    }
    

    我意识到,由愿意阅读手册的人群回答此类问题已成为一件苦差事,但如果你想进步,你应该看看,大多数苹果文档都写得非常好,因为这些事情过去了。 memory management guide 会解决很多问题。

    【讨论】:

    • 感谢 Harald,我查看了内存管理指南,但我猜想误解了 :( 我确实理解您所说的关于覆盖我最初的 alloc/init 的内容,但是我确实有一个关于那么 NSDictionary *collection = [jsonObjects valueForKey:collectionName]; 和 NSDictionary *collection = [NSDictionary dictionaryWithDictionary:[jsonObjects valueForKey:collectionName]]; 之间的功能差异,即这两个声明在功能上是等效的,文档没有说清楚吗?跨度>
    • 是和否,这两个调用都没有返回对您拥有的东西的引用(看起来它们都不包含'alloc'或'new'或'copy',但是首先创建一个新字典并用给定字典的值初始化它(称为“便利构造函数”),第二个只是返回一个相应的字典。[NSDictionary dictionaryWithDictionary:...] 不同 i> 比 [[NSDictionary alloc] initWithDictionary:...] 第二个确实创建了一个你拥有的对象
    • 感谢 Harald,您的帮助很大。
    【解决方案3】:

    在该代码中,您只是重新分配 lastAccess 指针,这会使 alloced NSNumber 泄露。您需要为lastAccess 指向的NSNumber 对象实际设置值。

    编辑:

    我已经放置了一些示例代码,但我现在将其取出,因为我现在意识到上面的代码示例存在太多问题。查看NSDictionary 的文档。使用collection,您正在创建一个对象,然后通过将其指针重新分配给其他对象来泄漏它。解决这些问题后,我建议使用新代码更新问题。

    【讨论】:

      【解决方案4】:

      按照上面的@bbum,我会这样写你的代码:

      for(NSString *collectionName in jsonObjects)
      {
      NSDictionary *collection = [jsonObjects valueForKey:collectionName];
      NSArray *items = [NSArray arrayWithObject:[collection valueForKey:@"items"]];
      NSNumber * lastAccess = [collection valueForKey:@"lastAccess"];
      }
      

      这种情况下的所有变量都会自动释放,因此您无需手动释放它们。

      【讨论】:

        猜你喜欢
        • 2012-06-06
        • 2012-01-30
        • 1970-01-01
        • 2012-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-26
        • 2016-05-16
        相关资源
        最近更新 更多