在for循环运行时退出应用程序

时间:2012-02-04 01:47:16

标签: iphone objective-c for-loop

在我的应用程序中,我有一个tableView,其中包含来自服务器的内容。要下载这些内容,我使用NSURLConnection并创建一个NSMutableArray(tableItems)来保存和管理我想要使用的图像的地址。

在connectionDidFinishLoading中,在填充tableItems之后,有这个for循环:

for (int i = 0; i < [tableItems count]; i++) {

        // HERE I CHECK IF THE IMAGE I'M LOOKING FOR IS ALREADY ON DISK
        NSString *pathToCheckImage = [NSString stringWithFormat:@"%@/%@.png", pathToPreviews, [tableItems objectAtIndex:i]];
        NSData *dataOfCheckImage = [NSData dataWithContentsOfFile:pathToCheckImage];
        UIImage *checkImage = [UIImage imageWithData:dataOfCheckImage];

        NSString *pathToImage;
        UIImage *image;
        if (checkImage != nil) {
            // THE IMAGE IS ALREADY ON DISK SO I GET IT FROM TEMP FOLDER
            image = checkImage;
        } else {

            // THE IMAGE IS NEW SO I HAVE TO GET THE IMAGE FROM THE SERVER
            pathToImage = [NSString stringWithFormat:@"http://www.SERVER.com/SERVER_PATH/%@.png", [tableItems objectAtIndex:i]];

            NSURL *url = [NSURL URLWithString:pathToImage];
            NSData *data = [NSData dataWithContentsOfURL:url];
            image = [UIImage imageWithData:data];

            // AND SAVE IT ON DISK
            NSString *path = [NSString stringWithFormat:@"%@/%@.png", pathToPreviews, [tableItems objectAtIndex:i]];
            [self cacheImageOnDisk:image withPath:path];
        }

        if (image != nil) {
            [arrayOfImages addObject:image];
        }

}

此代码正常工作,即使根据我必须从服务器下载的图像的数量和大小,执行任务可能需要1或2分钟。

问题是如果用户退出(按下主页按钮),而这个for循环正在运行,它会一直执行任务直到结束,即使它需要1分钟才能完成。

在此期间,再次启动应用程序不可避免地会在启动时崩溃。

我试图在退出时停止这个for循环,但是在for循环结束任务之前,不会调用applicationDidEnterBackground,applicationWillResignActive和applicationWillTerminate。

我试图设置“应用程序不在后台运行”,但没有任何改变。

任何建议都会非常感激。

2 个答案:

答案 0 :(得分:4)

您不应该在主线程上下载图像。该应用程序将无法响应。 Grand Central Dispatch是完成这些任务的简单方法。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSUInteger count = [tableItems count];
    for (int i = 0; i < count; i++) {
        // TODO: check if app didResignActive and break

        UIImage *image = ... // get image from disk or network

        // Add the image to the array on the main thread to avoid any threading issues
        dispatch_sync(dispatch_get_main_queue(), ^{
            [arrayOfImages addObject:image];
        });
    }
});

答案 1 :(得分:1)

你需要从主线程处理循环(很容易出错),或者将你的工作分解成块(更简单)。尝试将循环提取到一个运行10次的单独方法中,然后使用[... performSelector:@selector(myMethod)afterDelay:0]调度另一个运行;这将使runloop有机会每10次迭代循环和处理事件(如退出)。

线程(无论是通过较旧的方式还是较新的dispatch_async)仍然可以让你获得更好的响应能力,所以如果你想这样做,我的推荐就是这样:

在后台线程和主线程工作时共享无数据。

生成后台线程,完全使用其他地方无法访问的本地状态,然后使用完成的数组调回主线程。任何共享状态都很可能会让你的生活变得非常困难。