【问题标题】:Objective-C: Fixing memory management in a methodObjective-C:修复方法中的内存管理
【发布时间】:2010-10-10 05:12:05
【问题描述】:

我几乎理解了 Objective-C 中的简单引用计数/内存管理,但是我在使用以下代码时遇到了困难。我正在发布 mutableDict(在下面的代码中注释),它在我的代码中造成了有害行为。如果我让内存泄漏,它会按预期工作,但这显然不是这里的答案。 ;-) 你们中的任何一个更有经验的人会不会善意地指出我正确的方向,因为我可以重新编写任何这种方法来更好地处理我的内存占用?主要是我如何管理 NSMutableDictionary *mutableDict,因为这是这里的罪魁祸首。我想了解这个问题,而不仅仅是复制/粘贴代码——所以一些 cmets/feedback 是理想的。谢谢大家。

- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument 
                               withXPath:(NSString *)XPathStr {

    NSError *theError = nil;
    NSMutableArray *mutableArray = [[[NSMutableArray alloc] init] autorelease];
    //NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
    CXMLDocument *theXMLDocument = [[[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError] retain]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
    int i, j, cnt = [nodes count];
    for(i=0; i < cnt; i++) {
        CXMLElement *xmlElement = [nodes objectAtIndex:i];
        if(nil != xmlElement) {
            NSArray *attributes = [NSArray array];
            attributes = [xmlElement attributes];
            int attrCnt = [attributes count];
            NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
            for(j = 0; j < attrCnt; j++) {
                if([[[attributes objectAtIndex:j] name] isKindOfClass:[NSString class]]) 
                    [mutableDict setValue:[[attributes objectAtIndex:j] stringValue] forKey:[[attributes objectAtIndex:j] name]];
                else 
                    continue;
            }
            if(nil != mutableDict) {
                [mutableArray addObject:mutableDict];
            }
            [mutableDict release];  // This is causing bad things to happen.
        }
    }

    return (NSArray *)mutableArray;
}

【问题讨论】:

    标签: ios objective-c iphone cocoa cocoa-touch


    【解决方案1】:

    Memory Management Programming Guide 主题下从方法返回对象(向下滚动一点),有一些简单的示例说明如何从具有正确内存管理的方法返回对象。 p>

    【讨论】:

      【解决方案2】:

      好吧,释放 mutableDict 确实不应该引起任何问题,因为它上面的行(将 mutableDict 添加到 mutableArray)将自动保留它。虽然我不确定您的代码到底出了什么问题(您没有具体说明“坏事”是什么意思),但我会建议一些一般性的事情:

      1. 不要立即自动释放 mutableArray。让它成为一个常规的 alloc/init 语句,当你返回它时自动释放它(“return [mutableArray autorelease];”)。

      2. XMLDocument 正在泄漏,请务必在返回之前将其释放。此外,您不需要像现在一样保留它。 alloc/init 通过将对象保留计数从 1 开始来完成这项工作,再次保留它只是确保它永远泄漏。去掉retain,返回前释放,不会泄露。

      3. 只是提示:确保在其他地方使用此方法时保留该方法的返回值 - 结果已自动释放,除非您明确保留/释放它,否则无法保证在您需要它时会出现某处。

      否则,此代码应该工作。如果仍然没有,我会尝试的另一件事是 [mutableArray addObject:[mutableDict copy]] 以确保 mutableDict 在发布时不会给您带来任何问题。

      【讨论】:

      • “不要马上自动释放 mutableArray……当你返回它时自动释放它……”我不同意。如果我没有在同一行看到自动释放,我必须去找它以确保你没有泄漏它。
      【解决方案3】:

      这是对代码的等效重写:

      - (NSArray *)attributeDictionaries:(NSString *)xmlDocument withXPath:(NSString *)XPathStr {
          NSError *theError = nil;
          NSMutableArray *dictionaries = [NSMutableArray array];
          CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError]; 
          NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
      
          for (CXMLElement *xmlElement in nodes) {
              NSArray *attributes = [xmlElement attributes];
              NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
              for (CXMLNode *attribute in attributes) {
                  [attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
              }
      
              [dictionaries addObject:attributeDictionary];
          }
      
          [theXMLDocument release];
          return attributeDictionaries;
      }
      

      请注意,我只对 theXMLDocument 进行了引用计数。那是因为数组和字典超出了这个方法的范围。 arraydictionary 类方法创建 NSArrayNSMutableDictionary 对象的自动释放实例。如果调用者没有明确地保留它们,它们将在应用程序事件循环的下一轮自动释放。

      • 我还删除了永远不会执行的代码。 CXMLNode name 方法表示它返回一个字符串,因此测试将始终为真。
      • 如果mutableDictnil,你的问题就更大了。抛出异常比静默失败要好,所以我也取消了那个测试。
      • 我还使用了相对较新的 for 枚举语法,它消除了您的计数器变量。
      • 我重命名了一些变量和方法,使其更像 Cocoa 风格。 Cocoa 与大多数语言的不同之处在于,使用诸如“create”之类的动词通常被认为是不正确的,除非您特别想让调用者负责释放您返回的任何对象。
      • 你没有对theError 做任何事情。您应该检查它并报告错误,或者如果您不打算检查它,则传递nil。让应用构建一个您不会使用的错误对象是没有意义的。

      我希望这可以帮助您指明正确的方向。

      【讨论】:

      • Alex,我现在正在查看代码,但我马上看到的一个问题是,attributeDictionaries 在您返回之前会超出范围。
      • 我认为他只是打错了字(而且我没有足够的代表来编辑它)-我认为最后一行应该是“返回字典”。 attributeDictionary 实例被添加到这个数组中,所以它不会超出范围。
      猜你喜欢
      • 1970-01-01
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多