0

I need to get image size so accordingly I manage collection cell height. I use code to get image height is following:

for (NSURL*image1 in imageurlArray)
        {
            NSData *imageData = [NSData dataWithContentsOfURL:image1];
            UIImage *img = [UIImage imageWithData:imageData];
                CGSize finalsize;
                finalsize.height = 15+img.size.height+15+30+40;
                [_cellHeights addObject:@(finalsize.height)];
        }

But if I use this it will take 5 to 7 seconds to complete load in collection view(waterfall modal).

1 Answers1

0

The dataWithContentsOfURL will synchronously retrieve those images (which is especially problematic if those are not local file URLs). You almost never want to use this method, and certainly never from the main queue because it will block your app and you risk having your app killed by the watchdog process.

Also, because each of these requests are being performed synchronously, you’re doing these requests sequentially (it won’t start the next one until the previous one finishes). This magnifies the network latency issues.

If you absolutely must do this “fetch all images” process, you should do it asynchronously and concurrently. E.g. you can give your method a completion handler when all the requests are done:

- (void)fetchImageSizesWithCompletion:(void (^_Nonnull)(void))completion {
    dispatch_group_t group = dispatch_group_create();

    for (NSURL *url in imageurlArray) {
        dispatch_group_enter(group);
        NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (data != nil) {
                UIImage *image = [UIImage imageWithData:data];

                // do something with image.size

                // note, if updating UI, you should dispatch that back to the main queue, e.g.
                //
                // dispatch_async(dispatch_get_main_queue(), ^{
                //     // update UI here
                // });
            }
            dispatch_group_leave(group);
        }];
        [task resume];
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // do something when they're all done, e.g. call this methods completion handler
        completion();
    })
}

Probably even better, you shouldn’t try to load the images in advance, but let the cells request their respective images when they need them. And using self sizing cells (see UICollectionView Self Sizing Cells with Auto Layout) and when an image is retrieved, reload that cell.

Rob
  • 371,891
  • 67
  • 713
  • 902