7

How can i load images to a UICollectionview asynchronously? Inside following method?

- (PSTCollectionViewCell *)collectionView:(PSTCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

 bookImage = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", docPath, [[preview objectAtIndex:indexPath.row] lastPathComponent]]];
 [[cell grid_image] setImage:bookImage];

}

In viewdidload() i am using following asynch call to load images to "preview "NSMutablearray

 dispatch_queue_t imageLoadQueue = dispatch_queue_create("com.GMM.assamkar", NULL);

dispatch_async(imageLoadQueue, ^{
    //Wait for 5 seconds...
    usleep(1000000);
    docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];


    for(int k=0; k <[allImage count] ;k++){


        imgURL = [allImage objectAtIndex:k];
        [imagePreview addObject:imgURL];
        imgData=[NSData dataWithContentsOfURL:[NSURL URLWithString:imgURL]];


        [imgData writeToFile:[NSString stringWithFormat:@"%@/%@", docPath, [allImage lastPathComponent]] atomically:YES];

    }

    [[self collectionView] reloadData];


});

Please help me..Now its taking too much time for loading...

Vineet Singh
  • 4,775
  • 1
  • 28
  • 39
Navi
  • 1,634
  • 2
  • 16
  • 35

3 Answers3

9

Trying to answer your main question "How can i load images to a UICollectionview asynchronously?"

I would suggest solution offered by "Natasha Murashev" here, which worked nicely for me and it's simple.

If here imgURL = [allImage objectAtIndex:k]; in allImage property you keep array of URLs, then update your collectionView:cellForItemAtIndexPath: method like this:

- (PSTCollectionViewCell *)collectionView:(PSTCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSURL *url = [NSURL URLWithString:[allImage objectAtIndex:indexPath]];

    [self downloadImageWithURL:url completionBlock:^(BOOL succeeded, NSData *data) {
        if (succeeded) {
            cell.grid_image.image = [[UIImage alloc] initWithData:data];
        }
    }];
}

And add method downloadImageWithURL:completionBlock: to your class, which will load images asynchronously and update cells in CollectionView automatically when images are successfully downloaded.

- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, NSData *data))completionBlock
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if (!error) {
            completionBlock(YES, data);
        } else {
            completionBlock(NO, nil);
        }
    }];
}

I see you try to preload images before view appears so maybe my solution isn't what you what, but from your question it's hard to say. Any how, you can achieve what you want with this as well.

Swift 2.2 Solution in Swift.

public typealias ImageFetchCompletionClosure = (image: UIImage?, error: NSError?, imageURL: NSURL?) -> Void

extension String {
   func fetchImage(completionHandler: (image: UIImage?, error: NSError?, imageURL: NSURL?) -> Void) {
        if let imageURL = NSURL(string: self) {
            NSURLSession.sharedSession().dataTaskWithURL(imageURL) { data, response, error in
                guard
                    let httpURLResponse = response as? NSHTTPURLResponse where httpURLResponse.statusCode == 200,
                    let mimeType = response?.MIMEType where mimeType.hasPrefix("image"),
                    let data = data where error == nil,
                    let image = UIImage(data: data)
                    else {
                        if error != nil {
                            completionHandler(image: nil, error: error, imageURL: imageURL)
                        }
                        return
                }
                dispatch_sync(dispatch_get_main_queue()) { () -> Void in
                    completionHandler(image: image, error: nil, imageURL: imageURL)
                }
            }.resume()
        }
    }
}

Usage sample:

    "url_string".fetchImage { (image, error, imageURL) in
        // handle different results, either image was downloaded or error received
    }
Jonauz
  • 3,955
  • 1
  • 25
  • 22
  • 1
    Isn't it like cells can be reused and you efficiently overwrite the cell with some other image data? Also cell is undefined in your sample ;) – Ben Affleck Jul 03 '14 at 19:30
  • It's mainly meant to answer how to load images asynchronously, not how to work efficiently with cells :) Though, thanks for pointing it out. – Jonauz Jul 04 '14 at 22:57
0

This code creates serial queue:

dispatch_queue_t imageLoadQueue = dispatch_queue_create("com.GMM.assamkar", NULL);

therefore each task IN QUEUE is performed in the same thread successive. Therefore your single work thread is sustained by sleep for each task of loading that slow down all process of loading.

Use asynchronous CONCURRENT queue by using something like that:

dispatch_queue_t imageLoadQueue = dispatch_queue_create("com.GMM.assamkar", DISPATCH_QUEUE_CONCURRENT);
user2595925
  • 108
  • 5
  • So and use reloadData on the main thread. Like that dispatch_async(dispatch_get_main_queue(), ^{ //reloadData }); – user2595925 Aug 03 '13 at 09:11
  • i think i should use a new lazy loading method to disaplay for my PSTCollectionView – Navi Aug 03 '13 at 11:00
-1

Use Lazy Load File for your requirement.

LazyLoad.h
LazyLoad.m

Use them like this

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];

    [cell addSubview:[self addViewWithURL:@"http://openwalls.com/image/399/explosion_of_colors_1920x1200.jpg" NFrame:CGRectMake(0, 0, 50, 50)]];

    cell.backgroundColor=[UIColor blueColor];
    return cell;
}

-(UIView*)addViewWithURL:(NSString*)urlStr NFrame:(CGRect)rect
{
    LazyLoad *lazyLoading;

    lazyLoading = [[LazyLoad alloc] init];
    [lazyLoading setBackgroundColor:[UIColor grayColor]];
    [lazyLoading setFrame:rect];

    [lazyLoading loadImageFromURL:[NSURL URLWithString:urlStr]];
    return lazyLoading;
}

Download Demo Here

Warewolf
  • 12,416
  • 4
  • 55
  • 85
  • How can i display images in UICollectionview cell.imageview.image ,thats my question – Navi Aug 03 '13 at 12:42
  • cell.imageview.image property not exists in CollectionView only in tableView.MyCode will load image asynchronously and add as subview in collectionView cell. – Warewolf Aug 03 '13 at 12:48
  • add myCode with http://stackoverflow.com/a/17856406/1305001 or u need to use custom cell instead – Warewolf Aug 03 '13 at 12:50
  • your code is not working AND THE LINK FOR /H AND .M FILES ARE EMPTY – Navi Aug 03 '13 at 12:57
  • Heloo ,i need to disaply that in cell.image my custome cell imageview but u r using uiview . – Navi Aug 03 '13 at 13:05
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/34763/discussion-between-navi-and-hercules) – Navi Aug 03 '13 at 13:10
  • The LazyLoad class solved my initial problem but opened a new one. The images won't load before the view finishes to scroll. Is there a way to have them load as soon as they enter the screen while scrolling? – Roeliee Nov 28 '13 at 15:13