Как получить изображения из библиотеки фотографий в диапазоне двух дат в iOS?

Контекст

Я пытаюсь получить изображения в диапазоне двух дат из библиотеки фотографий.

Во-первых, я получаю информацию об изображениях библиотеки фотографий одно за другим в форме словаря и выбираю дату каждого изображения с помощью ключа и сравниваю эту дату с двумя датами, используя условие if.

Если дата этого изображения находится между двумя датами, я вставляю это изображение в массив.

Я сохраняю изображения в массиве, потому что хочу показать их в виде коллекции.

Проблема

Пока он работает на симуляторе, он не работает на реальном устройстве из-за проблем с памятью.

Я думаю, что в реальной библиотеке фотографий устройства есть куча изображений, поэтому у меня возникают проблемы с памятью.

Как я могу решить эту проблему?


person Chandan Reddy    schedule 20.09.2016    source источник
comment
Я добавил тег AlAssetsLibrary в ваш вопрос, чтобы избежать путаницы. Если вы хотите использовать библиотеку фотографий, дайте мне знать.   -  person NSNoob    schedule 20.09.2016
comment
хорошо, спасибо за тег AlAssetsLibrary. Я должен получать изображения только из библиотеки фотографий.   -  person Chandan Reddy    schedule 20.09.2016
comment
Я имею в виду эту платформу для фотографий, которая является обновленной заменой AssetsLibrary.   -  person NSNoob    schedule 20.09.2016
comment
Хорошо, я сделаю ... я думаю, что это лучше и новее   -  person Chandan Reddy    schedule 20.09.2016
comment
Смотрите обновленный ответ. Если у вас есть какие-либо вопросы, оставьте комментарий   -  person NSNoob    schedule 20.09.2016
comment
Хорошо позвольте мне проверить   -  person Chandan Reddy    schedule 20.09.2016


Ответы (2)


Согласно нашему разговору в комментариях, в котором вы согласились переключиться на Photos Framework вместо библиотеки активов, вместо сохранения изображений в свой массив сохраните локальный идентификатор 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;
} 

Вы можете создать startDate и endDate из него следующим образом:

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

Теперь вам нужно получить 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;
}

Теперь вы получаете PHFetchResults всех фотографий, существующих в этом диапазоне дат. Теперь, чтобы извлечь массив данных локальных идентификаторов, вы можете использовать этот метод:

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

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

Добавьте методы для извлечения/использования отдельных активов, когда они вам нужны.

Теперь вам понадобится 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);
        }
    });
}

Затем, используя этот 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);
                                }
                            }
                        }];
    });

}

Но не вызывайте эти методы напрямую, чтобы получить все желаемые изображения.

Вместо этого вызовите эти методы в своем методе 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
    }];

Заключение

Итак, в заключение:

  1. Вы можете решить свои проблемы с памятью, извлекая изображения только для видимых ячеек, а не извлекая их все.
  2. Вы можете оптимизировать свою производительность, извлекая изображения из фоновых потоков.

Если вы все равно хотите собрать все свои активы вместе, вы можете получить их с помощью fetchAssetCollectionWithLocalIdentifiers:, хотя я не рекомендую его.

Пожалуйста, оставьте комментарий, если у вас есть какие-либо вопросы или если у вас есть какие-либо другие отзывы.


Кредиты Линдси Скотт за установку предиката для запроса PHFetchResult для получения изображений между двумя датами в ее ответе здесь

person NSNoob    schedule 20.09.2016
comment
Спасибо за ваш повтор. Можете ли вы опубликовать код получения изображений между датами, потому что я не использую PHAsset, а использую ALAsset - person Chandan Reddy; 20.09.2016
comment
Библиотека фотографий @ChandanReddy лучше, чем библиотека активов. Не могли бы вы перейти на библиотеку фотографий? Если нет, этот ответ недействителен, и я его удалю. - person NSNoob; 20.09.2016
comment
У вас есть идея получить широту и длину изображения? - person Chandan Reddy; 28.09.2016
comment
Если он существует, вы можете получить его из PHAsset. Создайте новый вопрос, если хотите, и отправьте мне Ping, когда захотите. @ЧанданРедди - person NSNoob; 28.09.2016
comment
проверьте это stackoverflow.com/questions/39744762/ - person Chandan Reddy; 28.09.2016
comment
Привет ... есть еще одна проблема ... я получаю изображения между двумя днями, но не могу получить их между двумя временами в один и тот же день, что означает, например, между 8:30 и 9:30 утра. - person Chandan Reddy; 30.09.2016
comment
@ChandanReddy вы добавили компоненты времени при создании даты начала и окончания? Кстати, вместо того, чтобы расширять ветку комментариев здесь, вы всегда можете просто опубликовать новый вопрос о своей проблеме. - person NSNoob; 30.09.2016
comment
@ChandanReddy Да, я имею в виду их. Затем опубликуйте новый вопрос, объясните, как вы устанавливаете даты и в чем именно проблема. - person NSNoob; 30.09.2016
comment
Хорошо... я пропингую тебя - person Chandan Reddy; 30.09.2016
comment
проверьте это stackoverflow.com/questions/39788426/ - person Chandan Reddy; 30.09.2016

Почему вы сохраняете изображения в массиве. если изображение находится между двумя датами, просто сохраните имена изображений в массиве. а затем используйте приведенный ниже код, чтобы получить и использовать изображение по имени из библиотеки

NSString* photoName = [NSString stringWithFormat:@"%@.png",imageName];
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask, YES); 
NSString *path = [arrayPaths objectAtIndex:0];
NSString* imagePath = [path stringByAppendingPathComponent: photoName];
UIImage *image1=[UIImage imageWithContentsOfFile: imagePath];
imageView.image=image1;
person Muhammad Zeshan Arif    schedule 20.09.2016
comment
Сохранение изображений в массиве, потому что я хотел бы показать их в представлении коллекции - person Chandan Reddy; 20.09.2016
comment
сохранить имена в массиве, а в методе cellForItemAtIndexPath получить изображение, используя приведенный выше код, и показать его в представлении коллекции. - person Muhammad Zeshan Arif; 20.09.2016