【问题标题】:Memory Management Issue in iOS8, Objective CiOS8 中的内存管理问题,Objective C
【发布时间】:2015-01-29 08:37:50
【问题描述】:

所以这段代码在 iOS 8 之前对我有用,我已经在 iOS 7.1 的 3000 图像下载循环中对其进行了测试。

但最近我的一些 App 用户向我投诉了 App Crash While Image Download Process。

现在使用这种方式只有 200 张图片正在下载并且应用程序崩溃。

我刚刚发现,每次下载图片时,内存都会增加大约 0.6 到 0.8 MB,并且在大约 200 张图片应用程序崩溃之后。

我必须同步下载图像,因为当我尝试以Background ThreadAsynchronous mode 下载时,甚至尝试使用dispatch_async(dispatch_get_main_queue() 方式。几秒钟后进程开始,直到那时我使用的 While 循环才到达终点。

所以请在这个问题上帮助我。我该怎么做才能解决它。

我的图片下载代码是:

-(void) downloadImages
{
NSString *myDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
database = [dBName UTF8String];
if (sqlite3_open(database, &dbConnection) == SQLITE_OK)
{
    sqliteQuery = [NSString stringWithFormat: @"SELECT ProductID FROM ProductDetails WHERE ImageDownloadStatus = 0"];
    int i = 0;
    if (sqlite3_prepare_v2(dbConnection, [sqliteQuery UTF8String], -1, &sQLStatement, NULL) == SQLITE_OK)
    {
        while (sqlite3_step(sQLStatement) == SQLITE_ROW)
        {
            @autoreleasepool
            {
                temp = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(sQLStatement, 0)];
                NSString *imageURL = [NSString stringWithFormat:@"http://xxxxxxxxxxxxxxx.jpg",clientSite,temp];

                myImage = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];

                NSString *imagePath = [NSString stringWithFormat:@"%@/%@.jpg",myDirectory,temp];
                NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(myImage, 1.0f)];
                [imageData writeToFile:imagePath atomically:YES];

                sqliteQuery2 = [NSString stringWithFormat: @"UPDATE ProductDetails SET ImageDownloadStatus = 1 WHERE ProductID = \'%@\'",temp];
                 if (sqlite3_prepare_v2(dbConnection, [sqliteQuery2 UTF8String], -1, &sQLStatement2, NULL) == SQLITE_OK)
                 {
                     if (sqlite3_step(sQLStatement2) == SQLITE_DONE)
                      sqlite3_finalize(sQLStatement2);
                 }

                [self performSelectorInBackground:@selector(updateUILabels) withObject:nil];
                 i = i + 1;   
            }
        }
        sqlite3_finalize(sQLStatement);
    }
    sqlite3_close(dbConnection);
 }
}

-(void) updateUILabels
{
@autoreleasepool
{
    progressCounter.hidden = NO;
    lblProgressStatus.hidden = NO;
    spinner.hidden = NO;
    [spinner startAnimating];

    lblProgressStatus.text = @"Synchronising Product Images...";
    lblProgressCounter.text = [NSString stringWithFormat:@"%d / %d”, i,total];       
}
}

【问题讨论】:

  • 首先阅读有关 performSelectorInBackground stackoverflow.com/questions/19500820/… 的内容。也永远不要从后台线程更新 UI 元素。
  • @AndreasZ 我只是检查了这个[self performSelectorOnMainThread:@selector(updateUILabels:) withObject:nil waitUntilDone:NO];,但用户界面没有更新:(
  • dowloadImages 是否在后台线程上运行?如果不是简单地调用 [self updateUILabels]。但是,如果您不使用后台线程来下载图片,您将阻塞主线程。
  • @AndreasZ downloadImages 正在主线程上运行。我怎样才能阻塞主线程
  • 您应该在后台线程上执行 downloadImages。我在您的问题中写道“我必须同步下载图像,因为当我尝试在后台线程或异步模式下下载甚至尝试使用 dispatch_async(dispatch_get_main_queue() 方式时。进程在几秒钟后开始,直到那时我正在使用的循环只是到达终点。”当您说您正在使用的 while 循环到达终点时,您是什么意思?

标签: ios objective-c iphone memory-management ios8


【解决方案1】:

您应该在后台执行downloadImages 方法,在主线程中执行updatedUILabels 方法。您可以在主线程中使用dispatch_async(dispatch_get_main_queue(), ^{ [self updateUILabels]; });[self performSelectorOnMainThread:@selector(updateUILabels:) withObject:nil waitUntilDone:NO]; 执行updatedUILabels

通常始终在后台线程中执行长时间运行的操作(使用 GCD、NSOperations 或块)并始终在主线程上执行更新 UI 的函数。

【讨论】:

    猜你喜欢
    • 2011-05-11
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多