Les docs disent:
PHImageResultIsInCloudKey: valeur booléenne indiquant si les données d'actif photo sont stockées sur le périphérique local ou doivent être téléchargées à partir d'iCloud. (NSNumber) Si la réponse est OUI, aucune image n'a été fournie, car les données d'actif doivent être téléchargées à partir d'iCloud. Pour télécharger les données, soumettez une autre demande et spécifiez YES pour l'option networkAccessAllowed.
Mais cette clé est toujours OUI lorsqu'un élément est stocké dans la photothèque iCloud, même s'il est déjà complètement téléchargé sur l'appareil (téléchargé dans mon application, ouvert dans l'application Photos).
Si une image n'est pas disponible, je souhaite donner à l'utilisateur la possibilité de la télécharger (mais ne le faites pas automatiquement, du moins pas lorsqu'il n'y a pas de Wifi).
Alors, comment puis-je savoir si l'image doit être téléchargée?
Encore plus curieux: lorsque mon bloc de résultat requestImageForAsset:targetSize:contentMode:options:resultHandler:
est appelé pour une image à télécharger, je reçois un dernier appel avec wantedImage == nil, après la livraison d’une version plus petite et dégradée.
Dans ce cas, dégradé est NON, même si je n'ai aucune image et que l'image doit toujours être téléchargée à partir d'iCloud, seule une petite vignette de l'application Photos étant disponible localement jusqu'à présent.
J'ai testé cela sur des iPhone et des iPad avec différentes versions d'iOS 8 (8.1.x, 8.2 bêta, 8.3 bêta), le comportement est toujours le même.
Une fois que j'ai ouvert l'image dans l'application Photos, le dernier appel du gestionnaire de résultats contient l'image en taille réelle, mais PHImageResultIsInCloudKey sera toujours OUI.
Voici un code comment je demande les images:
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
}];
Je peux confirmer que PHImageResultIsInCloudKey n'est pas fiable. Pour les images stockées dans iCloud, il renvoie 1, même si l'image d'origine a été téléchargée sur l'appareil. Ce comportement est en contraste avec la documentation et je suggérerais de signaler un bogue à radar.Apple.com. À mon avis, PhotoKit reste un cadre très immature - il contient beaucoup de problèmes et quelques décisions de conception étranges.
Si vous appelez requestImageDataForAsset:
avec networkAccessAllowed
défini sur NO
, la imageData
renvoyée sera nil
si le clip n'est pas déjà téléchargé à partir d'iCloud. Sinon, les données réelles seront renvoyées, même si le clip est stocké dans 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
}
}
}];
Le meilleur moyen de vérifier si un ensemble PHAsset est toujours dans le nuage est d’essayer d’y accéder via PHImageManager avec networkAccessAllowed = NO. Si vous n’obtenez pas l’image/la ressource, sachez qu’elle est toujours dans le nuage ne pas être téléchargé):
+ (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);
}
}
Vous pouvez utiliser progressHandler pour vérifier si le PHAsset provient d'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.
});