简体   繁体   English

检测dispatch_async方法是否仍在运行

[英]Detect if a dispatch_async method is still running

I have a loadImages method 我有一个loadImages方法

- (void)loadImages {
   dispatch_async(dispatch_get_global_queue(0, 0), ^{
       //this method loads images from a url, processes them
       //and then adds them to a property of its view controller 
       //@property (nonatomic, strong) NSMutableArray *storedImages;
   });
}

When a button is clicked a view enters the screen, and all the images that currently exist in _storedImages are displayed 单击按钮后,视图进入屏幕,并显示_storedImages中当前存在的所有图像。

- (void)displayImages {
   for (NSString *link in _storedImages) {
      //displayImages
   }
}

The problem with this setup is, that if the user clicks the button before all the images are loaded, not all the images are presented on the screen. 此设置的问题是, 如果用户在加载所有图像之前单击该按钮,则不是所有图像都显示在屏幕上。

Hence, I would like to display an SVProgressHUD if the button is clicked, and the loadImages dispatch_async method is still running . 因此, 如果单击按钮,并且loadImages dispatch_async方法仍在运行 ,我想显示SVProgressHUD

So, how do I keep track of when this dispatch_async is completed? 那么, 如何跟踪此dispatch_async完成的时间? Because if I know this, then I can display an SVProgressHUD until it is completed. 因为如果知道这一点,那么我可以显示SVProgressHUD,直到完成为止。

On a side note, if you know how to load/display the images dynamically that info would be helpful too , ie you click the button and then as you see the current images, more images are downloaded and displayed 附带说明一下,如果您知道如何动态加载/显示图像,该信息也将有所帮助 ,即,单击按钮,然后在看到当前图像时,会下载并显示更多图像

Thank you from a first time iOS developer! 谢谢iOS初学者!


Ok I found a solution but it is incredibly inefficient , I am sure there's a better way to do this 好的,我找到了一个解决方案,但是效率非常低 ,我相信有更好的方法可以做到这一点

 1. Keep a boolean property doneLoadingImages which is set to NO 2. After the dispatch method finishes, set it to YES 3. In the display images method, have a while (self.doneLoadingImages == NO) //display progress HUD until all the images a loaded 

Keep in mind that NSMutableArray is not thread-safe. 请记住, NSMutableArray不是线程安全的。 You must ensure that you don't try to access it from two threads at once. 您必须确保不要尝试同时从两个线程访问它。

Using a boolean to track whether you're still loading images is fine. 使用布尔值跟踪您是否仍在加载图像就可以了。 Make loadImages look like this: 使loadImages看起来像这样:

- (void)loadImages {
    self.doneLoadingImages = NO;

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        while (1) {
            UIImage *image = [self bg_getNextImage];
            if (!image)
                break;
            dispatch_async(dispatch_get_main_queue(), ^{
                [self addImage:image];
            });
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            [self didFinishLoadingImages];
        });

    });
}

So we send ourselves addImage: on the main queue for each image. 因此,我们将自己发送给每个图像的主队列上的addImage: The addImage: method will only be called on the main thread, so it can safely access storedImages : addImage:方法将仅在主线程上被调用,因此它可以安全地访问storedImages

- (void)addImage:(UIImage *)image {
    [self.storedImages addObject:image];
    if (storedImagesViewIsVisible) {
        [self updateStoredImagesViewWithImage:image];
    }
}

We send ourselves didFinishLoadingImages when we've loaded all the images. 加载所有图像后,我们将自己发送didFinishLoadingImages Here, we can update the doneLoadingImages flag, and hide the progress HUD if necessary: 在这里,我们可以更新doneLoadingImages标志,并在必要时隐藏进度HUD:

- (void)didFinishLoadingImages {
    self.doneLoadingImages = YES;
    if (storedImagesViewIsVisible) {
        [self hideProgressHUD];
    }
}

Your button action can then check the doneLoadingImages property: 然后,您的按钮操作可以检查doneLoadingImages属性:

- (IBAction)displayImagesButtonWasTapped:(id)sender {
    if (!storedImagesViewIsVisible) {
        [self showStoredImagesView];
        if (!self.doneLoadingImages) {
            [self showProgressHUD];
        }
    }
}

What I usually do with this kind of problem is basically the following (rough sketch): 我通常对这种问题所做的基本上是以下内容(粗略的草图):

- (void)downloadImages:(NSArray*)arrayOfImages{

  if([arrayOfImages count] != 0)
  {
     NSString *urlForImage = [arrayOfImages objectAtIndex:0];
     // Start downloading the image

     // Image has been downloaded
     arrayOfImages = [arrayOfImages removeObjectAtIndex:0];
     // Ok let's get the next ones...
     [self downloadImages:arrayOfImages];
  }
  else
  {
   // Download is complete, use your images..
  }
}

You can pass the number of downloads that failed, or even a delegate that will receive the images after. 您可以传递失败的下载次数,甚至可以传递将在之后接收图像的委托。

You put a "note" and this may help, it allows you to display the images as they come down, I store the URLs in an array (here it is strings but you could do array of NSURL). 您放置一个“注释”,这可能会有所帮助,它允许您在图像下降时显示它们,我将URL存储在一个数组中(这里是字符串,但是您可以创建NSURL数组)。

for(NSString *urlString in imageURLs)
{
    // Add a downloading image to the array of images
    [storedImages addObject:[UIImage imageNamed:@"downloading.png"]];

    // Make a note of the image location in the array    
    __block int imageLocation = [storedImages count] - 1; 

    // Setup the request    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
    [request setTimeoutInterval: 10.0];
    request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

    [NSURLConnection sendAsynchronousRequest:request
                  queue:[NSOperationQueue currentQueue]
                  completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                  // Check the result
                  NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                  if (data != nil && error == nil && [httpResponse statusCode] == 200)
                  { 
                      storedImages[imageLocation] = [UIImage imageWithData:data];
                      [self reloadImages];
                  }
                  else
                  {
                      // There was an error
                      recommendedThumbs[imageLocation] = [UIImageimageNamed:@"noimage.png"];
                      [self reloadImages]
                  }
           }];
}

You then need another method which reloads the display. 然后,您需要另一种重新加载显示的方法。 If the images are in a table then [[tableview] reloaddata]; 如果图像在表中,则[[tableview] reloaddata];

-(void)reloadImages

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

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