I have a loadImages method
- (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
- (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 .
So, how do I keep track of when this dispatch_async is completed? Because if I know this, then I can display an SVProgressHUD until it is completed.
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!
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. 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:
- (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. The addImage:
method will only be called on the main thread, so it can safely access 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. Here, we can update the doneLoadingImages
flag, and hide the progress HUD if necessary:
- (void)didFinishLoadingImages {
self.doneLoadingImages = YES;
if (storedImagesViewIsVisible) {
[self hideProgressHUD];
}
}
Your button action can then check the doneLoadingImages
property:
- (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).
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];
-(void)reloadImages
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.