ios - Cómo identificar si un PHAsset no se ha descargado completamente de iCloud(por lo que debo solicitarlo nuevamente con options.networkAccessAllowed)
photokit (4)
Los docs dicen:
PHImageResultIsInCloudKey: un valor booleano que indica si los datos del activo de la foto se almacenan en el dispositivo local o se deben descargar desde iCloud. (NSNumber) En caso afirmativo, no se proporcionó ninguna imagen, ya que los datos de los activos deben descargarse de iCloud. Para descargar los datos, envíe otra solicitud y especifique SÍ para la opción networkAccessAllowed.
Pero esta clave siempre es SÍ cuando un recurso se almacena en la Biblioteca de fotos de iCloud, incluso cuando ya está completamente descargado en el dispositivo (lo descargué en mi aplicación, también lo abrí en la aplicación Fotos).
Si una imagen no está disponible, quiero darle al usuario la posibilidad de descargarla (pero no lo haga de forma automática, al menos no cuando no haya WiFi).
Entonces, ¿cómo puedo saber si la imagen necesita ser descargada?
Aún más curioso: cuando se llama a mi bloque de resultados de requestImageForAsset:targetSize:contentMode:options:resultHandler:
para una imagen que necesita ser descargada, recibo una última llamada con requestImage == nil, después de que se entregó una versión más pequeña y degradada.
En este caso, la degradación es NO, incluso si no obtuve ninguna imagen y la imagen aún tiene que descargarse desde iCloud, ya que solo una pequeña miniatura de la aplicación Fotos está disponible localmente hasta el momento.
Probé esto en iPhones y iPads con diferentes versiones de iOS 8 (8.1.x, 8.2 beta, 8.3 beta). El comportamiento es siempre el mismo.
Una vez que abrí la imagen en la aplicación Fotos, la última llamada del controlador de resultados tiene la imagen a tamaño completo, pero PHImageResultIsInCloudKey seguirá siendo SÍ.
Aquí hay un código de cómo solicito las imágenes:
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''s in the cloud, isDegraded is NO and PHImageResultIsInCloudKey is YES (as always) and requestedImage is nil
}];
La mejor manera de verificar si un PHAsset todavía está en la nube es intentar acceder a él a través de PHImageManager con networkAccessAllowed = NO, y si no obtiene la imagen / activo, entonces sabe que todavía está en la nube (y ganó no ser descargado):
+ (void)checkCloudStatusForPHAsset:(PHAsset*)phAsset completion:(void (^)(BOOL isInCloud))completionBlock
{
if (phAsset) {
if (phAsset.mediaType == PHAssetMediaTypeVideo) {
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
options.networkAccessAllowed = NO;
[[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
completionBlock(asset == nil);
}];
}
else if (phAsset.mediaType == PHAssetMediaTypeImage) {
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.version = PHImageRequestOptionsVersionOriginal;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeNone;
options.networkAccessAllowed = NO;
[[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
completionBlock(imageData == nil);
}];
}
else {
completionBlock(NO);
}
}
else {
completionBlock(NO);
}
}
Puede usar progressHandler para verificar si el PHAsset es de 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.
});
Puedo confirmar que PHImageResultIsInCloudKey no es confiable. Para las imágenes almacenadas en iCloud, devuelve 1, aunque la imagen original se haya descargado en el dispositivo. Este comportamiento contrasta con la documentación y sugeriría informar un error en radar.apple.com. En mi opinión, PhotoKit sigue siendo un marco muy inmaduro: contiene muchos problemas y también algunas decisiones conceptuales extrañas.
Si llama a requestImageDataForAsset:
con networkAccessAllowed
establecido en NO
, los datos de imagen devueltos serán nil
si el clip aún no se ha descargado de iCloud. De lo contrario, devolverá los datos reales, aunque el clip esté almacenado en 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
}
}
}];