【问题标题】:UITableView's NSString memory leak on iphone when encoding with NSUTF8StringEncoding使用 NSUTF8StringEncoding 编码时,iPhone 上 UITableView 的 NSString 内存泄漏
【发布时间】:2011-01-30 03:48:12
【问题描述】:

只有当 NSString 没有使用 NSASCIIStringEncoding 进行编码时,我的 UITableView 才会出现严重的内存泄漏问题。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"cell";
    UILabel *textLabel1;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        textLabel1 = [[UILabel alloc] initWithFrame:CGRectMake(105, 6, 192, 22)];

        textLabel1.tag = 1;
        textLabel1.textColor = [UIColor whiteColor];
        textLabel1.backgroundColor = [UIColor blackColor];
        textLabel1.numberOfLines = 1;
        textLabel1.adjustsFontSizeToFitWidth = NO;
        [textLabel1 setFont:[UIFont boldSystemFontOfSize:19]];
        [cell.contentView addSubview:textLabel1];
        [textLabel1 release];

    } else {
        textLabel1 = (UILabel *)[cell.contentView viewWithTag:1];
    }

    NSDictionary *tmpDict = [listOfInfo objectForKey:[NSString stringWithFormat:@"%@",indexPath.row]];

    textLabel1.text = [tmpDict objectForKey:@"name"];

    return cell;
}

-(void) readDatabase {
    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = [documentPaths objectAtIndex:0];
    databasePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@",myDB]];
    sqlite3 *database;

    if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {

        const char sqlStatement = [[NSString stringWithFormat:@"select id,name from %@ order by orderid",myTable] UTF8String];
        sqlite3_stmt *compiledStatement;
        if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
            while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
                NSString *tmpid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];


                NSString *tmpname = [NSString stringWithCString:(const char *)sqlite3_column_text(compiledStatement, 1) encoding:NSUTF8StringEncoding];


                [listOfInfo setObject:[[NSMutableDictionary alloc] init] forKey:tmpid];
                [[listOfInfo objectForKey:tmpid] setObject:[NSString stringWithFormat:@"%@", tmpname] forKey:@"name"];


            }
        }
        sqlite3_finalize(compiledStatement);

        debugNSLog(@"sqlite closing");

    }
    sqlite3_close(database);

}

当我换行时

NSString *tmpname = [NSString stringWithCString:(const char *)sqlite3_column_text(compiledStatement, 1) encoding:NSUTF8StringEncoding];

NSString *tmpname = [NSString stringWithCString:(const char *)sqlite3_column_text(compiledStatement, 1) encoding:NSASCIIStringEncoding];

内存泄漏消失了

我尝试了 NSString stringWithUTF8String,但它仍然泄漏。 我也试过:

NSData *dtmpname = [NSData dataWithBytes:sqlite3_column_blob(compiledStatement, 1) length:sqlite3_column_bytes(compiledStatement, 1)];
NSString *tmpname = [[[NSString alloc] initWithData:dtmpname encoding:NSUTF8StringEncoding] autorelease];

问题依然存在,当你开始滚动表格视图时发生泄漏。

我实际上尝试过其他编码,似乎只有 NSASCIIStringEncoding 有效(没有内存泄漏)

如果我在关闭视图之前没有滚动表格视图,则根本没有泄漏。实际上 listOfInfo 本身并没有泄漏,因为当我删除该行时不会发生泄漏

textLabel1.text = [tmpDict objectForKey:@"name"];

任何想法/解决方法如何摆脱这个问题?

注意:我确实有

for (id theKey in listOfInfo) {
   [[listOfInfo objectForKey:theKey]  release];
}
[listOfInfo release];

已经在dealloc上

【问题讨论】:

  • 那里有很多代码!...如果问题的原因是编码类型,我会感到惊讶。现在检查您的代码以尝试找出真正的问题...
  • 我也很惊讶。我花了整整一周的时间来解决这个问题,幸运的是,当我将编码更改为 ASCII 时,我发现问题完全消失了。
  • 来自苹果的回复:不幸的是,这是亚洲字体的一个已知问题。目前还没有解决此问题的 ETA。如果您还没有这样做,那么您绝对应该在此记录一个新错误,以便让工程人员意识到它正在影响许多开发人员。此外,我将在 7263420 中添加注释,强调紧急性并引用此事件。
  • 这可能是模拟器与实际设备的问题。稍后会确认(本周末不在我的开发盒上),但同时在实际设备上尝试配置文件。

标签: iphone memory-leaks uitableview sqlite nsstring


【解决方案1】:

你的程序中的漏洞其实就在这里:

[listOfInfo setObject:[[NSMutableDictionary alloc] init] forKey:tmpid];

您正在分配字典并且从不释放它,因此它会泄漏。你应该写:

[listOfInfo setObject:[[[NSMutableDictionary alloc] init] autorelease] forKey:tmpid];

[listOfInfo setObject:[NSMutableDictionary dictionary] forKey:tmpid];

由于此字典包含您的字符串,因此字符串会与字典一起泄漏。更改为 NSASCIIStringEncoding 并不能修复此泄漏,它可能只是伪装它(因为随后需要转换字符串并且泄漏可能不会将其跟踪到其新位置)或者转换可能完全失败(如果字符串可以' t 转换为 ASCII)。

【讨论】:

  • 我确实在 dealloc 上有 [listOfInfo release]。它不能自动释放,因为我在其他地方需要这个变量。实际上我的泄漏与 listOfInfo 无关。如果我没有滚动表格视图,则根本没有泄漏。
  • 实际上,如果视图在任何滚动操作之前解除分配。它根本不会泄漏。 “泄漏”显示没有问题,使用“对象分配”滚动数百条记录,在视图解除分配后会有几 MB 内存泄漏,并且在几次内很容易崩溃。用 ascii 编码也可以。
  • 发布 listOfInfo 不会修复我列出的泄漏。 listOfInfo 和您使用 setObject:forKey: 添加到其中的字典是两个不同的字典。
  • 我有 for (id theKey in listOfInfo) { [[listOfInfo objectForKey:theKey] release]; } [listOfInfo 发布];实际上,它与 listOfInfo 泄漏本身无关,并且正在处理中。泄漏太明显,更改为 ASCII 编码将立即解决问题。另请注意,如果您在关闭视图之前没有滚动表格视图,则根本不会泄漏。
猜你喜欢
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
相关资源
最近更新 更多