简体   繁体   English

iPhone-GCD第一次不起作用

[英]iPhone - GCD doesn't work for the first time

In my app, I load image from the URL: 在我的应用程序中,我从URL加载图像:

-(void)loadImages
{
    ...

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

In order to avoid blocking the main thread until the download has completed I call this method in -viewDidAppear using GCD : 为了避免在下载完成之前阻塞主线程,我使用GCD-viewDidAppear中调用此方法:

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

However, when I open my view controller with the imageView at the first time, the imageView is empty (even if I wait for a long time) but after I open this view controller again and image appears and everything is good to go. 但是,当我第一次使用imageView打开view controller时, imageView是空的(即使我等待了很长时间),但是当我再次打开此view controller并且出现图像后,一切都很好。

Where is my mistake ? 我的错误在哪里? Sorry, new to multithreading :) 抱歉,多线程新手:)

EDIT : I also forgot to mention, that I use the image in the tableView when I get it: 编辑 :我也忘了提一下,当我得到它时,我在tableView使用图像:

 cell.imageView.image = image1;

UIElements in iOS should always be updated via main thread. iOS中的UIElement应始终通过主线程进行更新。 What you could do is:- 您可以做的是:-

   __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];
    });
    });

or Else you there is a better way of fetching images from URL by using AFNetworking. 否则,您可以使用AFNetworking从URL获取图像的更好方法。 It is faster and easier. 它更快,更容易。 You just have to write one line of code:- 您只需要编写一行代码:-

[cell.imageView setImageWithURL:imgUrl1];

This may not be the answer that you were looking for, but that's not the recommended way to load URLs. 这可能不是您要找的答案,但这不是建议的加载URL的方法。 You should use the URL loading classes available such as NSURLRequest and NSURLConnection. 您应该使用可用的URL加载类,例如NSURLRequest和NSURLConnection。

Try this: 尝试这个:

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];
    }
}];

You need to inform the view that the image needs to be redrawn. 您需要通知视图该图像需要重绘。 Add: 加:

[imageView setNeedsDisplay];

to the end of your loadImages method. loadImages方法的末尾。

You have many problems here: 您在这里遇到许多问题:

  1. You can not start networking requests on an thread not running a runloop. 您无法在未运行Runloop的线程上启动网络请求。
  2. You can not update your UI from a thread other than the main thread. 您不能从主线程以外的其他线程更新UI。
  3. [NSData dataWithContentsOfURL:imgUrl1] is not a safe way to load an external resource, even on a different thread (but especially on the main thread). [NSData dataWithContentsOfURL:imgUrl1]并不是加载外部资源的安全方法,即使在其他线程上(尤其是在主线程上)也是如此。
  4. Any time you dispatch to a different thread, you run the risk that your table cell has been recycled and is no longer showing the data you think it is. 每当您分派到另一个线程时,都将面临表单元已被回收并且不再显示您认为是的数据的风​​险。 (It's still the same cell instance, but is now showing some other row's data.) (它仍然是相同的单元格实例,但是现在正在显示其他行的数据。)

What you should be doing: 您应该做什么:

  1. Start your network operation using asynchronous calls on the main thread. 使用主线程上的异步调用启动网络操作。 (You can use another thread or queue if you want, but you need to make sure it's running a runloop.) (如果需要,可以使用另一个线程或队列,但是需要确保它正在运行运行循环。)
  2. From your delegate messages, dispatch your image decoding on a different thread. 从您的委托消息中,将图像解码分派到另一个线程上。
  3. After the image is decoded, dispatch back to the main thread to update it. 图像解码后,分派回主线程进行更新。
  4. Before actually assigning the image, check that the cell is still being used for the purpose you think. 在实际分配图像之前,请检查该单元是否仍在用于您认为的目的。

You can solve the first three problems by using AFNetworking . 您可以使用AFNetworking解决前三个问题。 It wraps the delegate methods and lets you just provide a success and failure block. 它包装了委托方法,并让您仅提供成功和失败块。 AFNetworking's AFImageRequestOperation in particular bounces code between queues as I've described. 正如我所描述的,AFNetworking的AFImageRequestOperation特别是在队列之间反弹代码。 (It even runs its main networking loop in a different thread, which isn't necessary but since it does it well, why not?) (它甚至在不同的线程中运行其主要的网络循环,这不是必需的,但是既然做得很好,为什么不呢?)

You'll still need to verify the cell's identity. 您仍然需要验证单元格的身份。

Since you are using it in TableView, add [self.tableView reloadData]; 由于您在TableView中使用它,因此添加[self.tableView reloadData]; in the end of loadImages method. 在loadImages方法的末尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM