如何清除NSString相关的内存泄漏?

时间:2009-08-24 09:24:26

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

在我的应用程序中,此方法显示内存泄漏如何删除泄漏?

-(void)getOneQuestion:(int)flashcardId categoryID:(int)categoryId
{   

    flashCardText = [[NSString alloc] init];
    flashCardAnswer=[[NSString alloc] init];
    //NSLog(@"%s %d %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

    sqlite3 *MyDatabase;
    sqlite3_stmt *CompiledStatement=nil;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *MyDatabasePath = [documentsDirectory stringByAppendingString:@"/flashCardDatabase.sqlite"];
    if(sqlite3_open([MyDatabasePath UTF8String],&MyDatabase) == SQLITE_OK)
    {
        sqlite3_prepare_v2(MyDatabase, "select flashCardText,flashCardAnswer,flashCardTotalOption from flashcardquestionInfo where flashCardId=? and categoryId=?", -1, &CompiledStatement, NULL);
        sqlite3_bind_int(CompiledStatement, 1, flashcardId);
        sqlite3_bind_int(CompiledStatement, 2, categoryId);
        while(sqlite3_step(CompiledStatement) == SQLITE_ROW)
        {       
            self.flashCardText = [NSString stringWithUTF8String:(char *)sqlite3_column_text(CompiledStatement,0)];
            self.flashCardAnswer= [NSString stringWithUTF8String:(char *)sqlite3_column_text(CompiledStatement,1)];
            flashCardTotalOption=[[NSNumber numberWithInt:sqlite3_column_int(CompiledStatement,2)] intValue];
        }
        sqlite3_reset(CompiledStatement);
        sqlite3_finalize(CompiledStatement);
        sqlite3_close(MyDatabase);
    }

}

这种方法也显示泄漏.....这种方法有什么问题?

-(void)getMultipleChoiceAnswer:(int)flashCardId
 {  
if(optionsList!=nil)
    [optionsList removeAllObjects];
else
    optionsList = [[NSMutableArray alloc] init];

sqlite3 *MyDatabase;
sqlite3_stmt *CompiledStatement=nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *MyDatabasePath = [documentsDirectory stringByAppendingString:@"/flashCardDatabase.sqlite"];
if(sqlite3_open([MyDatabasePath UTF8String],&MyDatabase) == SQLITE_OK)
{
    sqlite3_prepare_v2(MyDatabase,"select OptionText from flashCardMultipleAnswer where flashCardId=?", -1, &CompiledStatement, NULL);
    sqlite3_bind_int(CompiledStatement, 1, flashCardId);
    while(sqlite3_step(CompiledStatement) == SQLITE_ROW)
    {       
        [optionsList addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(CompiledStatement,0)]];
    }
    sqlite3_reset(CompiledStatement);
    sqlite3_finalize(CompiledStatement);
    sqlite3_close(MyDatabase);
}   

}

alt text http://www.freeimagehosting.net/uploads/5b8120982c.png

4 个答案:

答案 0 :(得分:4)

您实际上并未使用在函数顶部初始化的对象:

flashCardText = [[NSString alloc] init];
flashCardAnswer=[[NSString alloc] init];

在您稍后将这些对象替换为其他对象时

self.flashCardText = [NSString stringWithUTF8String:(char *)sqlite3_column_text(CompiledStatement,0)];
self.flashCardAnswer= [NSString stringWithUTF8String:(char *)sqlite3_column_text(CompiledStatement,1)];

所以那些似乎是泄漏的物体。

答案 1 :(得分:2)

[[NSString alloc] init]完全没有意义。除了更多的工作之外,它将返回完全相同的@“”。它不太可能泄漏,因为系统几乎肯定会返回一个固定的常量空字符串,在init例程中释放[NSString alloc]。但这是毫无意义,毫无用处和糟糕的代码。

除此之外,您的代码看起来还不错。第二种方法可能被认为是“泄漏”了optionsList,只是因为它创建它并且它永远不会被释放,但它只创建一次所以应该没问题。

尝试运行程序并进行泄漏检测,然后打破调试器并使用

po 0x4b2720(替换为泄漏对象的地址)

查看实际泄漏的字符串。

请记住,泄漏可能会产生误报,尤其是在缓存任何内容的情况下。

答案 2 :(得分:1)

[[NSString alloc] init];是一个无用的短语。删除两个第一行将消除泄漏。

编辑:请注意,除非保留自动释放池,否则一旦自动释放池耗尽,从数据库中提取的两个字符串将会消失。

Redit:关于第二种方法;我看不出任何明显的泄漏。 NSCFStrings创建了很多,并经常坚持下去。这并不意味着他们实际上是泄密。从我所看到的,该方法中的所有内容都是自动释放或持久的。

答案 3 :(得分:1)

-1/2

@""相当于[[[NSString alloc] init] autorelease]; [[NSString alloc] init]会泄漏。

请记住规则:init/retain应由autorelease/release平衡。