Как определить, не полностью ли загружен PHASset из iCloud (поэтому мне нужно снова запросить параметры options.networkAccessAllowed)

В документах говорится:

PHImageResultIsInCloudKey: Логическое значение, указывающее, хранятся ли данные фотоактивности на локальном устройстве или должны быть загружены из iCloud. (NSNumber) Если ДА, изображение не было предоставлено, поскольку данные о ресурсе должны быть загружены из iCloud. Чтобы загрузить данные, отправьте другой запрос и укажите YES для параметра networkAccessAllowed.

Но этот ключ всегда есть, когда ресурс хранится в iCloud Photo Library, даже если он уже полностью загружен на устройство (скачал его в моем приложении, также открыл его в приложении "Фото" ).

Если изображение недоступно, я хочу дать пользователю возможность его загрузить (но не делайте этого автоматически, по крайней мере, когда нет Wifi).

Итак, как мне узнать, нужно ли загружать изображение?

Еще более любопытно: когда мой результирующий блок requestImageForAsset:targetSize:contentMode:options:resultHandler: вызывается для изображения, которое нужно загрузить, я получаю последний вызов с запросомImage == nil после того, как была поставлена ​​меньшая и деградированная версия.

В этом случае ухудшение равно NO, даже если у меня нет изображения, и изображение все равно должно быть загружено из iCloud, так как только небольшое уменьшенное изображение из приложения "Фотографии" доступно локально до сих пор.

Я тестировал это на iPhones и iPads с разными версиями iOS 8 (8.1.x, 8.2 beta, 8.3 beta), поведение всегда одно и то же.

Как только я открыл изображение в приложении "Фото", последний вызов обработчика результатов имеет полноразмерный образ, но PHImageResultIsInCloudKey все равно будет YES.

Вот некоторый код, как я запрашиваю изображения:

PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
options.networkAccessAllowed = NO;

[self.imageManager requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *requestedImage, NSDictionary *info) {
    // Checking for requestedImage and the info keys here
    // When a full sized image was loaded, the result of PHImageResultIsInCloudKey is still YES
    // When a full sized image couldn't be loaded cause it in the cloud, isDegraded is NO and PHImageResultIsInCloudKey is YES (as always) and requestedImage is nil
}];

Ответы

Ответ 1

Я могу подтвердить, что PHImageResultIsInCloudKey не является надежным. Для изображений, хранящихся в iCloud, он возвращает 1, даже если исходное изображение было загружено на устройство. Такое поведение отличается от документации, и я предлагаю сообщить об ошибке на сайте radar.apple.com. PhotoKit, на мой взгляд, все еще очень незрелая структура - в ней много проблем, а также некоторые странные концептуальные решения.

Ответ 2

Если вы вызываете requestImageDataForAsset: с networkAccessAllowed, установленным в NO, возвращаемый imageData будет nil, если клип еще не загружен из iCloud. В противном случае он вернет фактические данные, даже если клип сохранен в iCloud.

PHImageManager *manager = [PHImageManager defaultManager];    
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.networkAccessAllowed = NO;
[manager
 requestImageDataForAsset:asset
 options:options
 resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
    if ([[info valueForKey:PHImageResultIsInCloudKey] boolValue]) {
    // Image is in iCloud
        if (imageData) {
            // Image is downloaded
        } else {
            // Image is not downloaded
        }
    }
 }];

Ответ 3

Вы можете использовать progressHandler, чтобы проверить, является ли PHASset от iCloud.

__block BOOL isPhotoInICloud = NO;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){

    isPhotoInICloud = YES;
    // some code to update the download progress
});
options.networkAccessAllowed = YES;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.synchronous = NO;

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
// use the options to get the high quality image for only once time.
});