0

在我的应用程序中,我从 URL 加载图像:

-(void)loadImages
{
    ...

    image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:imgUrl1]];
}

为了避免在下载完成之前阻塞主线程,我在 -viewDidAppear中使用以下方法调用此方法GCD

dispatch_async( dispatch_get_global_queue(0,0), ^{
            [self loadImages];
        });

然而,当我第一次打开我view controllerimageView时候,它imageView是空的(即使我等了很长时间)但是当我view controller再次打开它并且图像出现并且一切都很好。

我的错误在哪里?抱歉,多线程新手 :)

编辑:我也忘了提到,我在tableView得到它时使用了图像:

 cell.imageView.image = image1;
4

5 回答 5

2

iOS 中的 UIElements 应该始终通过主线程进行更新。你可以做的是: -

   __block NSData *data;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appName", NULL);
    dispatch_async(myQueue, ^{
       data = [NSData dataWithContentsOfURL:imgUrl1];
       dispatch_async(dispatch_get_main_queue(), ^(void) {
       cell.imageView.image = [UIImage imageWithData = data];
    });
    });

否则,您有更好的方法可以使用 AFNetworking 从 URL 获取图像。它更快更容易。你只需要写一行代码:-

[cell.imageView setImageWithURL:imgUrl1];
于 2013-04-01T17:15:28.707 回答
2

这可能不是您要寻找的答案,但这不是加载 URL 的推荐方式。您应该使用可用的 URL 加载类,例如 NSURLRequest 和 NSURLConnection。

试试这个:

NSURLRequest *imageRequest = [[NSURLRequest alloc] initWithURL:imageURL];
[NSURLConnection sendAsynchronousRequest:imageRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
    if (!error) {
        UIImage *image = [[UIImage alloc] initWithData:data];
        [imageView setImage:image];
    }
}];
于 2013-04-01T17:16:20.737 回答
1

您需要通知视图图像需要重绘。添加:

[imageView setNeedsDisplay];

到你的loadImages方法结束。

于 2013-04-01T17:09:01.230 回答
1

你这里有很多问题:

  1. 您不能在未运行 runloop 的线程上启动网络请求。
  2. 您不能从主线程以外的线程更新您的 UI。
  3. [NSData dataWithContentsOfURL:imgUrl1]即使在不同的线程上(尤其是在主线程上),也不是加载外部资源的安全方法。
  4. 每当您分派到不同的线程时,您都会面临表格单元格已被回收并且不再显示您认为的数据的风​​险。(它仍然是同一个单元格实例,但现在显示了一些其他行的数据。)

你应该做什么:

  1. 在主线程上使用异步调用启动您的网络操作。(如果需要,您可以使用另一个线程或队列,但您需要确保它正在运行一个运行循环。)
  2. 从您的委托消息中,将您的图像解码分派到不同的线程上。
  3. 图像解码后,派回主线程进行更新。
  4. 在实际分配图像之前,请检查单元格是否仍在用于您认为的目的。

您可以使用AFNetworking解决前三个问题。它包装了委托方法,让您只提供一个成功和失败块。正如我所描述的, AFNetworking 的AFImageRequestOperation特别是在队列之间反弹代码。(它甚至在不同的线程中运行它的主网络循环,这不是必需的,但既然它做得很好,为什么不呢?)

您仍然需要验证单元格的身份。

于 2013-04-02T06:20:49.243 回答
0

既然是在TableView中使用,添加[self.tableView reloadData]; 在 loadImages 方法的最后。

于 2013-04-01T17:33:06.263 回答