12

I am working on an application that relies on showing lots of photos on screen from multiple sources.

I am wondering how could apple make that "photo tile" view in their photo app? With that much photos, in my opinion the app should give memory warning with less photos (even if i load photos in "thumbnail size") displayed at once, but i can see that it can show hundreds of photos in one screen when i zoom out.

One way i can think of is these views are not individual photos but they are single 'tiled' images generated from photos on real time, so the app just shows 2-3 photos at once. But this still needs lots of cpu power and time to generate that fast. I can zoom in or out instantly .

I want to achieve similar functionality in my app, any directions on how to achieve this would be great.

Thanks for answers.

IOS 7 Photos.app

dreampowder
  • 1,644
  • 3
  • 25
  • 41
  • why would it consume too much memory if thumbnail size is small as that? – dadalar Oct 10 '14 at 11:00
  • @DenizAdalar because there are too many photos. also loading an "ALAsset" is way too slow to load that much photos in realtime (each of them is loaded in a separate thread) in my opinion. – dreampowder Oct 10 '14 at 11:02
  • I wanted to implement something like this a few days back,in the Year view, my collection view just can't scroll smoothly. – gabbler Oct 10 '14 at 11:08
  • @CarouselMin yes that is my point, i think photos.app is doing something different than just putting smaller images – dreampowder Oct 10 '14 at 11:11

2 Answers2

12

I have made some research and found that IOS8 has a wonderful new framework called "Photos Framework"

This Framework lets you easily cache images, call thumbnail images with predefined sizes and load items. (old ALAsset library just had one "thumbnail" size, you had to resize your own.)

on my test a screen full of 20x20 photos (my phones screen content 384 images), app only takes 10mb's of memory, and almost no flickering when scrolling. Smooth scrolling can be achieved by optimizing cell reloading imo.

Heres the code i've used for loading images into a uicollectionview with 20x20 item size:

@import Photos;
@interface MainViewController ()

@property (strong) PHFetchResult *assetsFetchResults;
@property (strong) PHCachingImageManager* imageManager;

@end

on viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.imageManager = [[PHCachingImageManager alloc] init];

    CGFloat scale = [UIScreen mainScreen].scale;
    CGSize cellSize = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize;
    AssetGridThumbnailSize = CGSizeMake(cellSize.width * scale, cellSize.height * scale);

    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
    self.assetsFetchResults = [PHAsset fetchAssetsWithOptions:nil];
    // Do any additional setup after loading the view.
}

and collection view datasource methods:

#pragma mark <UICollectionViewDataSource>

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.assetsFetchResults.count;
}

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

    [self.imageManager requestImageForAsset:self.assetsFetchResults[indexPath.item] 
                                 targetSize:CGSizeMake(20, 20) 
                                contentMode:PHImageContentModeAspectFill 
                                    options:nil resultHandler:^(UIImage *result, NSDictionary* info){

                                        UIImageView* imgView = (UIImageView*)[cell.contentView viewWithTag:999];
                                        if(!imgView) {
                                            imgView = [[UIImageView alloc] initWithFrame:[cell.contentView bounds]];
                                            imgView.tag = 999;
                                            [cell.contentView addSubview:imgView];
                                        }
                                        imgView.image = result;
                                    }];
    // Configure the cell

    return cell;
}

Thats it!

dreampowder
  • 1,644
  • 3
  • 25
  • 41
  • Could you provide a sample project, I modified the photos code from apple,only changing the collection view item size to 20x20, I get a usage of 15.6MB memory usage on my iPhone 4S, scrolling is not that smooth. AssetGridThumbnailSize is 40x40 though since scale is 2 for 4S, so the target size is also 40x40 instead of 20x20. How did you achieve only 10MB memory usage by optimising cell reloading? – gabbler Oct 11 '14 at 09:47
  • 1
    @CarouselMin i am also testing on iphone4s btw, heres the project: https://github.com/dreampowder/photosSample – dreampowder Oct 11 '14 at 13:56
  • I tested the project and its memory usage is 10mb~11mb, which is better,only that the image is a little blurry,changing the targetSize:CGSizeMake(20, 20) to targetSize:CGSizeMake(40, 40) make photos clear, but usage goes up to 11~12mb, scrolling is a little bit slow, anyway it is better than the origin code, which caches some photos when scrolling. – gabbler Oct 11 '14 at 15:23
  • yes image looks blurry but keep in mind that you are reducing a 5-8megapixel image to 20x20 size :) – dreampowder Oct 12 '14 at 20:08
  • 4
    I don't think you're caching any images by using the PHCachingImageManger. In order to cache images you need to call this method on the PHCachingImageManager, startCachingImagesForAssets(_:targetSize:contentMode:options:) – Salman Hasrat Khan Dec 21 '14 at 15:05
  • @SalmanHasratKhan you are right, i forgot caching the loaded image if it doesnt exist, thanks i will update the code – dreampowder Dec 22 '14 at 16:04
  • @AlexanderScholz i forgot updating the code, but still works as advertised :) – dreampowder Jun 26 '15 at 08:29
2

Apple example of using PHCachingImageManager is much better, as it's also using preheating text so that it caches correct resources. Please check it out https://github.com/robovm/apple-ios-samples/blob/master/ExampleappusingPhotosframework/SamplePhotosApp/AAPLAssetGridViewController.m

Vivienne Fosh
  • 1,751
  • 17
  • 24