iPhone SDK 中的 NSMutableArray、NSArray、NSString 内存泄漏
Posted
技术标签:
【中文标题】iPhone SDK 中的 NSMutableArray、NSArray、NSString 内存泄漏【英文标题】:Memory leak in NSMutableArray, NSArray, NSString in iPhone SDK 【发布时间】:2011-04-16 10:57:28 【问题描述】:在我的应用程序中,我在 NSMutableArray、NSArray 和 NSString 中遇到了内存泄漏。
这里是代码。
NSString *subQuery = [NSString stringWithFormat:@"SELECT %@ FROM tbl_lang WHERE glossary = '%@'",append1,glossaryName];
NSArray *subArray1 = [[[self returnExecuteQuery:subQuery] mutableCopy] autorelease];
[subArray addObjectsFromArray:subArray1];
NSString *columnQuery = [NSString stringWithFormat:@"select AutoID,%@ from tbl_lang where glossary='%@'",lblshortName.text,glossaryName];
NSArray *newArray =[[[self returnExecuteQuery:columnQuery] mutableCopy] autorelease];
[langArray addObjectsFromArray:newArray];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i=0; i<[newArray count]; i++)
NSString *cellText = [[newArray objectAtIndex:i] valueForKey:[NSString stringWithFormat:@"%@",lblshortName.text]];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:@""] )
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[tempArray addObject:[NSString stringWithFormat:@"%@ : %@",lblshortName.text, decodedString3]];
else
[tempArray addObject:@"<empty>"];
NSString *detail = @"_________________";
for (int j=0; j<[lableNameArray count]; j++)
NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:[NSString stringWithFormat:@"%@",[lableNameArray objectAtIndex:j]]];
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
detail = [NSString stringWithFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4];
[detailTextArray addObject:detail];
当我在 Instruments 中运行时,我遇到了泄漏
-subArray1 在第二行。
-第二个for循环中的详细信息(NSString)。
而 subArray 和 langArray 是我的全局数组。
如果我从 NSArray *newArray =[[[self returnExecuteQuery:columnQuery] mutableCopy] autorelease];
和 NSArray *subArray1 = [[[self returnExecuteQuery:subQuery] mutableCopy] autorelease];
中删除 mutableCopy
,则 subArray 和 langArray 不会保留值。
如何避免这段代码中的内存泄漏?
【问题讨论】:
-returnExecuteQuery:
是做什么的?它返回一个拥有或非拥有的对象?它的合同是否说明了多次调用的返回值有效性?
你发布 tempArray 吗?在哪里?此外,尝试在 addObjectsFromArray 之后释放 subArray1 和 newArray(而不是自动释放它们)。
@Fran :我试图在 main for 循环之后释放两个数组,但它给了我 subArray 和 langArray 的 EXEC_BAD_ACCESS 错误。
@Bavarious : returnExecuteQuery
给了我从数据库中提取的 NSArray。
我得到了同样的警告......这是我的截图和question ..
【参考方案1】:
Olease 试试这个,在上面的代码中,您创建了两个属于自动释放池的多个对象,这是我尝试处理这些字符串变量的释放的一个版本。
其次,detail
的泄漏是因为您在代码中多次取消引用它。对于subArray1
,请查看评论
NSMutableString *subQuery =[ [NSMutableString alloc] initWithFormat:@"SELECT %@ FROM tbl_lang WHERE glossary = '%@'",append1,glossaryName];
// please make returnExecuteQuery's returned array autorelease if it is not.
NSArray *subArray1 = [[self returnExecuteQuery:subQuery] mutableCopy] ;
[subArray addObjectsFromArray:subArray1];
[subQuery release];
NSMutableString *columnQuery ==[ [NSMutableString alloc] initWithFormat:@"select AutoID,%@ from tbl_lang where glossary='%@'",lblshortName.text,glossaryName];
NSArray *newArray =[[self returnExecuteQuery:columnQuery] mutableCopy] ;
[langArray addObjectsFromArray:newArray];
[columnQuery relese];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i=0; i<[newArray count]; i++)
NSMutableString *tempKey = [[NSMutableString alloc]initWithFormat:@"%@",lblshortName.text]];
NSString *cellText = [[newArray objectAtIndex:i] valueForKey:tempKey];
[tempKey release];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:@""] )
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
NSMutableString *tempString = [[NSMutableString alloc] initWithFormat:@"%@ : %@",lblshortName.text, decodedString3]];
[tempArray addObject:tempString];
[tempString release];
else
[tempArray addObject:@"<empty>"];
NSMutableString *detail = nil;
for (int j=0; j<[lableNameArray count]; j++)
detail = [[ NSMutableString alloc]initWithString:@"_________________"];
NSMutableString *key = [[NSMutableString alloc]initWithFormat:@"%@",[lableNameArray objectAtIndex:j]];
NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:key];
[key release];
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[detail setString:[NSString stringWithFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
[detailTextArray addObject:detail];
[detail release];
[subArray1 release];
[newArray release];
UPDATE
: 请务必阅读代码中的 cmets 并回复,以便改进。
NSMutableString *subQuery =[ [NSMutableString alloc] initWithFormat:@"SELECT %@ FROM tbl_lang WHERE glossary = '%@'",append1,glossaryName];
//*****NOTE THIS POINT ----> please make returnExecuteQuery's returned array autorelease if it is not.
NSArray *subArray1 = [[self returnExecuteQuery:subQuery] mutableCopy] ;
[subArray addObjectsFromArray:subArray1];
[subQuery release];
NSMutableString *columnQuery ==[ [NSMutableString alloc] initWithFormat:@"select AutoID,%@ from tbl_lang where glossary='%@'",lblshortName.text,glossaryName];
//*****NOTE THIS POINT ----> please make returnExecuteQuery's returned array autorelease if it is not.
NSArray *newArray =[[self returnExecuteQuery:columnQuery] mutableCopy] ;
[langArray addObjectsFromArray:newArray];
[columnQuery relese];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i=0; i<[newArray count]; i++)
NSMutableString *tempKey = [[NSMutableString alloc]initWithFormat:@"%@",lblshortName.text]];
NSString *cellText = [[newArray objectAtIndex:i] valueForKey:tempKey];
[tempKey release];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:@""] )
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
NSMutableString *tempString = [[NSMutableString alloc] initWithFormat:@"%@ : %@",lblshortName.text, decodedString3]];
[tempArray addObject:tempString];
[tempString release];
else
[tempArray addObject:@"<empty>"];
NSMutableString *detail = [[ NSMutableString alloc]initWithString:@"_________________"];
for (int j=0; j<[lableNameArray count]; j++)
NSMutableString *key = [[NSMutableString alloc]initWithFormat:@"%@",[lableNameArray objectAtIndex:j]];
NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:key]; //also here if you note you are using subArray1 not subArray?
[key release];
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[detail setString:[NSString stringWithFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
break;//I am not sure why you are checking this condition but assume that you want to get NOT NULL VALUE and add it to array?
[detailTextArray addObject:detail];
[detail release];
[subArray1 release];
[newArray release];
更新 2:
if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[detail appendFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
谢谢,
【讨论】:
感谢代码,但仍然存在一些问题,我想在 for 循环后添加[detailTextArray addObject:detail]; [detail release];
,它显示 detail
中的泄漏。 subArray1 和 newArray 在 Instruments 中仍然显示泄漏。
请看上面的代码并回答代码中的cmets,这样场景可以更清楚。谢谢
在第一个和第二个 cmets 中:数组是自动释放的。第三条评论:我正在检查空值或空白值的条件。如果 checknull 不是空白或 null,则应在详细字符串后面附加 \n
。这样我就可以在单元格的详细信息中显示它。
@Meghan,我已经更新了详细字符串附加操作的代码。请确保您正确释放数组【参考方案2】:
不确定是什么导致了内存泄漏,但这可能会有所帮助。这是一种更直接的复制数组的方法,并且可能会导致避免泄漏:
NSArray *langArray =[[NSArray alloc] initWithArray: [self returnExecuteQuery:columnQuery] copyItems: YES];
这基本上是对 returnExecuteQuery 返回的数组进行一级深拷贝。您可以在Collections Programming Topics 中详细了解它。
我不确定 mutableCopy 是如何工作的,这可能与泄漏有关。如果它复制旧数组中的对象,然后将它们添加到新数组中,它们可能会以 2 的保留计数进入数组(1 来自副本,1 来自被添加到数组。)它不会很明显它应该以这种方式工作。但是,如果确实如此,那可能是泄漏的原因。
【讨论】:
@salo.dm:感谢您的回复。在某些情况下它对我有帮助。它仍然在detail
、subArray1
和newArray
中显示泄漏。
如果您使用此代码,则不需要 newArray。您可以删除引用 newArray 的整行。同样,您可以通过将代码中的第 2 行和第 3 行替换为以下代码来取消 subArray1: NSArray *subArray =[[NSArray alloc] initWithArray: [self returnExecuteQuery:subQuery] copyItems: YES];
dm:每次调用此方法时,都会在 langArray 中添加新的数据。所以这对我没有帮助【参考方案3】:
你可以从释放你的 tempArray 开始(在循环之后)。
通常,较高级别的泄漏隐藏在较低级别的洪水中(即容器泄漏会导致其所有内容也泄漏),您的字符串可能就是这种情况。
顺便说一句,使用mutableCopy] autorelease];
很好。
【讨论】:
以上是关于iPhone SDK 中的 NSMutableArray、NSArray、NSString 内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
UITableViewCell : ContentView 中的 UIImageView 与 iPhone SDK 中的图像重叠。