如何在iOS中的两个日期范围内从照片库中获取图像?

Cha*_*ddy 1 objective-c uiimage ios alassetslibrary phasset

上下文

我尝试从照片库中获取两个日期范围内的图像.

首先,我在字典表格中逐个获取照片库图像的信息,并使用键选择每个图像日期,并使用if条件将该日期与两个日期进行比较.

如果该图像的日期位于两个日期之间,我将该图像插入到数组中.

我正在保存数组中的图像,因为我想在集合视图中显示它们.

问题

虽然它在模拟器上运行,但由于内存问题,它无法在真实设备上运行.

我认为真实设备照片库中有大量图像,这就是为什么会出现内存问题.

我怎么解决这个问题?

NSN*_*oob 5

根据我们在评论中的对话,您同意切换到Photos Framework而不是Assets Library,而不是将图像保存到阵列,将PHAsset的本地标识符保存到阵列中.

获取位于日期范围内的图像的本地标识符

要按日期获取图像,首先创建一个实用程序方法来创建日期,为了可重用性:

-(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;
} 
Run Code Online (Sandbox Code Playgroud)

你可以像这样从它创建startDate和endDate:

NSDate *startDate = [self getDateForDay:11 andMonth:10 andYear:2015];
NSDate *endDate = [self getDateForDay:15 andMonth:8 andYear:2016];
Run Code Online (Sandbox Code Playgroud)

现在你需要从照片库中获取存在于此范围之间的FetchResults.使用此方法:

-(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;
}
Run Code Online (Sandbox Code Playgroud)

现在您可以获得PHFetchResults此日期范围内存在的所有照片.现在要提取本地标识符的数据数组,可以使用以下方法:

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

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

添加方法以在需要时获取/利用单个资产

现在,您将需要PHAsset图像.您可以像这样使用LocalIdentifier来获取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];
        if(savedAssets.count>0)
        {
            successBlock(savedAssets[0]);
        }
        else
        {
            NSError *error;
            failureBlock(error);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

然后使用它PHAsset,您可以获得所需大小的图像(尝试尽可能减少内存使用量):

-(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
                           targetSize:targetSize
                          contentMode:PHImageContentModeDefault
                              options:requestOptions
                        resultHandler:^void(UIImage *image, NSDictionary *info) {
                            @autoreleasepool {

                                if(image!=nil){
                                    successBlock(image);
                                }
                            }
                        }];
    });

}
Run Code Online (Sandbox Code Playgroud)

但是不要直接调用这些方法来获取所需的所有图像.

相反,在您的cellForItemAtIndexPath方法中调用这些方法,如:

 //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
    }];
Run Code Online (Sandbox Code Playgroud)

结论

总之:

  1. 您可以通过仅获取可见单元格的图像来处理您的内存问题,而不是获取它们的全部内容.
  2. 您可以通过在后台线程上获取图像来优化性能.

如果你想要将所有资产集中在一起,你可以使用fetchAssetCollectionWithLocalIdentifiers:方法来获取它,尽管我会建议反对它.

如果您有任何疑问或有任何其他反馈,请发表评论.


致Lyndsey Scott的信用,将谓词设置为PHFetchResult,请求在答案中获取两个日期之间的图像

  • 谢谢你很棒...投票和接受:-) (2认同)