Chandan Reddy Chandan Reddy - 1 year ago 66
Objective-C Question

How to fetch images from photo library within range of two dates in iOS?


I am try to fetch images within range of two dates from the photo library.

Firstly, I am getting info of the photo library images one by one in the dictionary form and picking every image date by using key and comparing that date with two dates by using if condition.

If that image's date lies between the two dates, I insert that image into array.

I am Saving images in array because I would like to show them in a collection view.


While it is working on simulator, it is not working on real device because of memory issues.

I think there are bunch of images in the real device photo library that's why am getting memory issues.

How can I solve this problem?

Answer Source

As per our conversation in comments in which you agreed to switch to Photos Framework instead of Assets Library, Rather than saving the images to your array, save the PHAsset's local identifier to your array.

Get the Local Identifiers of the images which lie in your date range

To get Images by Date, first create a utility method to create date, for reusability's sake:

-(NSDate*) getDateForDay:(NSInteger) day andMonth:(NSInteger) month andYear:(NSInteger) year{
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    [comps setDay:day];
    [comps setMonth:month];
    [comps setYear:year];
    NSDate *date = [[NSCalendar currentCalendar] dateFromComponents:comps];
    return date;

You can create startDate and endDate from it like this:

NSDate *startDate = [self getDateForDay:11 andMonth:10 andYear:2015];
NSDate *endDate = [self getDateForDay:15 andMonth:8 andYear:2016];

Now you need to get the FetchResults from Photo Library which exist between this range. Use this method for that:

-(PHFetchResult*) getAssetsFromLibraryWithStartDate:(NSDate *)startDate andEndDate:(NSDate*) endDate
    PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
    fetchOptions.predicate = [NSPredicate predicateWithFormat:@"creationDate > %@ AND creationDate < %@",startDate ,endDate];
    PHFetchResult *allPhotos = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions]; 
    return allPhotos;

Now you get the PHFetchResults of all the Photos which exist within this date range. Now to extract your Data Array of local identifiers, you can use this method:

-(NSMutableArray *) getAssetIdentifiersForFetchResults:(PHFetchResult *) result{

    NSMutableArray *identifierArray = [[NSMutableArray alloc] init];
    for(PHAsset *asset in result){
        NSString *identifierString = asset.localIdentifier;
        [identifierArray addObject:identifierString];
    return identifierArray;

Add Methods to fetch/utilize the individual assets when you need them

Now, you will need the PHAsset for the image. You can use the LocalIdentifier like this to get PHAsset:

-(void) getPHAssetWithIdentifier:(NSString *) localIdentifier andSuccessBlock:(void (^)(id asset))successBlock failure:(void (^)(NSError *))failureBlock{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSArray *identifiers = [[NSArray alloc] initWithObjects:localIdentifier, nil];
        PHFetchResult *savedAssets = [PHAsset fetchAssetsWithLocalIdentifiers:identifiers options:nil];
            NSError *error;

Then using this PHAsset, you can get the image for your required size (Try to keep it as minimum as possible to minimize memory usage):

-(void) getImageForAsset: (PHAsset *) asset andTargetSize: (CGSize) targetSize andSuccessBlock:(void (^)(UIImage * photoObj))successBlock {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        PHImageRequestOptions *requestOptions;

        requestOptions = [[PHImageRequestOptions alloc] init];
        requestOptions.resizeMode   = PHImageRequestOptionsResizeModeFast;
        requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
        requestOptions.synchronous = true;
        PHImageManager *manager = [PHImageManager defaultManager];
        [manager requestImageForAsset:asset
                        resultHandler:^void(UIImage *image, NSDictionary *info) {
                            @autoreleasepool {



But don't call these method directly to get all the images you desire.

Instead, call these methods in your cellForItemAtIndexPath method like:

 //Show spinner
[self getPHAssetWithIdentifier:yourLocalIdentifierAtIndexPath andSuccessBlock:^(id assetObj) {
        PHAsset *asset = (PHAsset*)assetObj;
        [self getImageForAsset:asset andTargetSize:yourTargetCGSize andSuccessBlock:^(UIImage *photoObj) {
            dispatch_async(dispatch_get_main_queue(), ^{
                //Update UI of cell
                //Hide spinner
                cell.imgViewBg.image = photoObj;
    } failure:^(NSError *err) {
       //Some error occurred in fetching the image


So in conclusion:

  1. You can handle your memory issues by fetching only the images for visible cells instead of fetching the whole lot of them.
  2. You can optimize your performance by fetching the images on background threads.

If you want to get all your assets together anyways, you can get it using fetchAssetCollectionWithLocalIdentifiers: method though I will recommend against it.

Please drop a comment if you have any questions or if you have any other feedback.

Credits to Lyndsey Scott for setting predicate to PHFetchResult request for getting images between two dates in her answer here