3

更新:我编辑了代码,但问题仍然存在......

大家好,
这是我在这里的第一篇文章——我发现这个地方是解决我许多问题的好资源。通常我会尽力自己解决任何问题,但这次我真的不知道出了什么问题,所以我希望有人能帮助我。
我正在构建一个使用 TouchXML 解析几个 xml 文件的 iPhone 应用程序。我有一个类 XMLParser,它负责下载和解析结果。当我使用同一个 XMLParser 实例多次解析一个 xml 文件时,我遇到了内存泄漏。这是解析片段之一(只是相关部分):

for(int counter = 0; counter < [item childCount]; counter++) {  
        CXMLNode *child = [item childAtIndex:counter];
        if([[child name] isEqualToString:@"PRODUCT"]) 
        {
            NSMutableDictionary *product = [[NSMutableDictionary alloc] init];
            for(int j = 0; j < [child childCount]; j++) {
                CXMLNode *grandchild = [child childAtIndex:j];
                if([[grandchild stringValue] length] > 1) {
                    NSString *trimmedString = [[grandchild stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                    [product setObject:trimmedString forKey:[grandchild name]];
                }
            }

            // Add product to current category array
            switch (categoryId) {
                case 0:
                    [self.mobil addObject: product];
                    break;
                case 1:
                    [self.allgemein addObject: product];
                    break;
                case 2:
                    [self.besitzeIch addObject: product];
                    break;
                case 3:
                    [self.willIch addObject: product];
                    break;
                default:
                    break;
            }
            [product release];
        }

    }  

第一次,我解析 xml 没有泄漏显示在仪器中,下次我这样做时,我得到了很多泄漏(NSCFString / NSCFDictionary)。当我深入研究泄漏的对象时,
仪器将我指向CXMLNode.m 中的这一部分:

theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString];
if ( _node->type != CXMLTextKind )
   xmlFree(theXMLString);
}

return(theStringValue);  

我真的花了很长时间并尝试了多种方法来解决这个问题,但到目前为止无济于事,也许我错过了一些重要的东西?

任何帮助都非常感谢,谢谢!

4

3 回答 3

3

问题可能出在这一行:

[self.mobil addObject:[product copy]];

通过调用副本,product您正在创建一个保留计数为 1 的新 NSMutableDictionary 实例。mobil但是,当您向其发送消息时,该实例将增加副本的保留计数addObject:,因此副本的保留计数现在为 2。一般来说,一个对象负责处理它自己的对象内存,所以任何时候你发消息setFoo:addObject:,你可以直接传递对象,即使它是自动释放的,或者你打算在调用后立即释放它;如果需要保留它,接收者有责任保留您传递的对象。

因为您没有将副本分配给任何变量,所以您没有指针可用于减少副本的保留计数,因为您不再对它感兴趣,因此即使mobil在某个时候释放产品副本,副本永远不会达到 0 的保留计数。您[product release]在 for 循环末尾的语句会释放原始product对象,而不是您创建的副本。

相反,请尝试以下方法,看看仪器是否更快乐:

[self.mobil addObject:product];
于 2009-06-20T11:18:55.593 回答
1

简单来说,每次使用时copy,还得在某处使用release/ 。autorelease

在这种情况下,更简单的答案是一开始就不要使用,因为在复制copy原始版本之后,您没有对原始版本做任何事情。product

于 2009-06-20T11:54:14.617 回答
1

我自己解决了这个问题。这有点愚蠢,但也许有人可能会遇到同样的事情,所以我要把它贴在这里。

1)我将可变数组设置为这样的实例变量:

@interface XMLParser : NSObject {

// ...  
NSMutableArray *mobil;  
// ...  
}   
@property(nonatomic, retain) NSMutableArray *mobil;  
@end  

每次我想恢复里面的新数据时,我都会这样做:
self.mobil = nil;
这不是我想做的,所以这是更好的方法:
[self.mobil removeAllObjects];

2) dealloc 方法必须像这样来修复泄漏(因为 mobil 被定义为属性):
-(void)dealloc {
[mobil release];
self.mobil = 无;
}

唷,这需要做很多工作才能找到 - 希望它可以节省其他人一些时间:-)

于 2009-06-20T15:41:05.300 回答