【问题标题】:iPhone - database reading method and memory leaksiPhone - 数据库读取方法和内存泄漏
【发布时间】:2011-02-10 04:59:31
【问题描述】:

在我的应用程序(一个 RSS 阅读器)中,我遇到了无法修复的内存泄漏,因为我无法理解它们的来源。这是 Instruments 指出的代码。

-(void) readArticlesFromDatabase {



[self setDatabaseInfo];

 sqlite3 *database;

 articles = [[NSMutableArray alloc] init];

 if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
  const char *sqlStatement = "select * from articles";
  if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
   while(sqlite3_step(compiledStatement) == SQLITE_ROW) {

    NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
    NSString *aDate = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
    NSString *aUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
    NSString *aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
    NSString *aAuthor = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
    NSString *aSummary = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
    NSMutableString *aContent = [NSMutableString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 7)];
    NSString *aNbrComments = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 8)];
    NSString *aCommentsLink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 9)];
    NSString *aPermalink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 11)];

    [aContent replaceCharactersInRange: [aContent rangeOfString: @"http://www.mywebsite.com/img/action-on.gif"] withString: @"hellocoton-action-on.gif"];
    [aContent replaceCharactersInRange: [aContent rangeOfString: @"hhttp://www.mywebsite.com/img/action-on-h.gif"] withString: @"hellocoton-action-on-h.gif"];
    [aContent replaceCharactersInRange: [aContent rangeOfString: @"hthttp://www.mywebsite.com/img/hellocoton.gif"] withString: @"hellocoton-hellocoton.gif"];

    NSString *imageURLBrut = [self parseArticleForImages:aContent];    
    NSString *imageURLCache = [imageURLBrut stringByReplacingOccurrencesOfString:@":" withString:@"_"];
    imageURLCache = [imageURLCache stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
    imageURLCache = [imageURLCache stringByReplacingOccurrencesOfString:@" " withString:@"_"];

    NSString *uniquePath = [tmp stringByAppendingPathComponent: imageURLCache];
    if([[NSFileManager defaultManager] fileExistsAtPath: uniquePath]) {
     imageURLCache = [@"../tmp/" stringByAppendingString: imageURLCache];
     [aContent replaceCharactersInRange: [aContent rangeOfString: imageURLBrut ] withString: imageURLCache];
    }

    Article *article = [[Article alloc] initWithName:aName date:aDate url:aUrl category:aCategory author:aAuthor summary:aSummary content:aContent commentsNbr:aNbrComments commentsLink:aCommentsLink commentsRSS:@"" enclosure:aPermalink enclosure2:@"" enclosure3:@""];

    [articles addObject:article];

    article = nil;
    [article release];
   }
  }
  sqlite3_finalize(compiledStatement);

 }
 sqlite3_close(database);
}

`

我有很多“文章”泄露,并且 NSString 与这些使用匹配:

[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, X)];

我尝试了很多不同的代码,但总是有这些漏洞。有人有什么想法可以帮助我吗?

【问题讨论】:

    标签: iphone database nsstring memory-leaks


    【解决方案1】:

    您泄露文章是因为:

    article = nil;
    [article release];
    

    你为什么试图释放 nil?

    只需将行设置文章删除为零,不需要。鉴于上述示例,该代码中可能存在更多问题。

    【讨论】:

    • 感谢您的回答。我试图添加这个,因为我已经在这一点上工作了很长时间,并且我正在寻找它。正如您所说,问题并非来自那一点(根据仪器,它不会改变任何东西(有或没有))。您说该代码中还有很多问题,您知道为什么这些行会造成泄漏吗: NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];感谢您的宝贵时间和帮助。
    • 删除分配为 nil 将阻止您的泄漏文章。
    • 您还泄漏了数组“articles”,应该在方法结束时释放它。如果要将其保留为实例变量,则应使用属性赋值。
    • 即使没有“article = nil;”,它仍然会泄漏“article”。关于数组“articles”我稍后使用它,我需要保留它,所以我在dealloc中释放它。
    【解决方案2】:

    我最近几天一直在跟踪这个问题,下面为我解决了这个问题。

    为您的文章 NSObject 添加一个 dealloc 方法并释放所有字符串。然后在您的 readArticlesFromDatabase 方法中首先发布文章,然后执行您的 init。

    【讨论】:

      【解决方案3】:

      我终于自己找到了部分解决方案。

      我的错误是将“文章”数组初始化为我的函数。事实上,每次我调用我的函数时,我都会丢失这个数组中以前的数据。 现在我在启动过程中初始化了“articles”数组,我只是在我的函数中删除了它的内容:

      - (void)applicationDidFinishLaunching:(UIApplication *)application {
             // My Code
             articles = [[NSMutableArray alloc] init];
             // My Code
      }
      

      然后

      -(void) readArticlesFromDatabase {
      
          [self setDatabaseInfo];
          sqlite3 *database;
      
          [articles removeAllObjects];
      
          if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
              const char *sqlStatement = "select * from articles";
              sqlite3_stmt *compiledStatement;
              if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
                  while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
      
                      NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
                      NSString *aDate = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
                      NSString *aUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
                      NSString *aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
                      NSString *aAuthor = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
                      NSString *aSummary = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
                      NSMutableString *aContent = [NSMutableString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 7)];
                      NSString *aNbrComments = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 8)];
                      NSString *aCommentsLink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 9)];
                      NSString *aPermalink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 11)];
      
                      [aContent stringByReplacingOccurrencesOfString: @"http://www.mywebsite.com/img/action-on.gif" withString: @"hellocoton-action-on.gif"];
                      [aContent stringByReplacingOccurrencesOfString: @"http://www.mywebsite.com/img/action-on-h.gif" withString: @"hellocoton-action-on-h.gif"];
                      [aContent stringByReplacingOccurrencesOfString: @"http://www.mywebsite.com/img/hellocoton.gif" withString: @"hellocoton-hellocoton.gif"];
      
                      NSString *imageURLBrut = [self parseArticleForImages:aContent]; 
                      NSString *imageURLCache = [imageURLBrut stringByReplacingOccurrencesOfString:@":" withString:@"_"];
                      [imageURLCache stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
                      [imageURLCache stringByReplacingOccurrencesOfString:@" " withString:@"_"];
      
                      NSString *uniquePath = [tmp stringByAppendingPathComponent: imageURLCache];
                      if([[NSFileManager defaultManager] fileExistsAtPath: uniquePath]) {
                          imageURLCache = [@"../tmp/" stringByAppendingString: imageURLCache];
                          [aContent replaceCharactersInRange: [aContent rangeOfString: imageURLBrut ] withString: imageURLCache];
                      }
      
                      Article *article = [[Article alloc] initWithName:aName date:aDate url:aUrl category:aCategory author:aAuthor summary:aSummary content:aContent commentsNbr:aNbrComments commentsLink:aCommentsLink commentsRSS:@"" enclosure:aPermalink enclosure2:@"" enclosure3:@""];
      
                      [articles addObject:article];
      
                      [article release];
                  }
              }
              sqlite3_finalize(compiledStatement);
          }
          sqlite3_close(database);
      }
      

      现在我必须关注由 [articles removeAllObjects] 引起的“文章”泄漏。 如果我不删除所有对象,我没有任何泄漏,但如果我这样做,我有泄漏。任何想法?如何在不泄漏这些文章对象的情况下清空数组?

      【讨论】:

      • 当你说“NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];”时,aName 必须被释放。否则会引发内存泄漏。
      猜你喜欢
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      • 2010-11-23
      • 2011-12-10
      • 2011-05-24
      • 2023-03-20
      相关资源
      最近更新 更多