web-dev-qa-db-fra.com

Cadre Photos. requestImageForAsset renvoyant deux résultats. Impossible de définir la vue de l'image

J'utilise donc la bibliothèque SwipeView ( https://github.com/nicklockwood/SwipeView ) pour afficher des images à l'aide du framework Photos pour iOS8.

Cependant, lorsque j'appelle requestImageForAsset, je remarque que je reçois deux résultats, une taille de vignette et la taille plus grande que je souhaite. Cependant, la plus grande image n'est pas chargée (elle s'appelle async, je comprends) à temps pour revenir, elle renvoie donc la petite image. 

Ce code pourrait avoir plus de sens.

    func swipeView(swipeView: SwipeView!, viewForItemAtIndex index: Int, reusingView view: UIView!) -> UIView! {
            let asset: PHAsset = self.photosAsset[index] as PHAsset

    var imageView: UIImageView!

    let screenSize: CGSize = UIScreen.mainScreen().bounds.size
    let targetSize = CGSizeMake(screenSize.width, screenSize.height)


    var options = PHImageRequestOptions()
//        options.deliveryMode = PHImageRequestOptionsDeliveryMode.Opportunistic
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact


    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
        println("huhuhuh")
        println(result.size)
        println(info)
        imageView = UIImageView(image: result)
    })
    println("setting view)
    return imageView
}

Voici la sortie du journal:

Enteredhuhuhuh
(33.5,60.0)
SETTING VIEW
huhuhuh
(320.0,568.0)

Comme vous pouvez le constater, la vue de l'image est renvoyée avant la réception de la grande image. Comment puis-je lui faire renvoyer cette image plus grande afin qu'elle ne montre pas la vignette?

Merci. 

21
Jonovono

Lire l'en-tête de la classe PHImageManager

Si - [PHImageRequestOptions isSynchronous ] renvoie NO (ou que les options sont Nil), resultHandler peut être appelé une ou plusieurs fois. Typiquement dans cette cas, resultHandler sera appelé de manière asynchrone sur le thread principal avec les résultats demandés. Cependant, si deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic, resultHandler peut être appelé de manière synchrone sur le thread appelant si des données d'image sont Immédiatement disponible. Si les données d'image sont retournées lors de cette première passe est de qualité insuffisante, resultHandler sera appelé à nouveau, de manière asynchrone sur le fil principal à un moment ultérieur avec le "correct" résultats. Si la demande est annulée, resultHandler ne peut pas être appelé du tout. Si - [PHImageRequestOptions isSynchronous] renvoie YES, resultHandler sera appelé exactement une fois, de manière synchrone et sur le fil d'appel. Les demandes synchrones ne peuvent pas être annulées. resultHandler pour les requêtes asynchrones, toujours appelé sur le thread principal

Donc, ce que vous voulez faire, c’est que vous appelez resultHandlersynchronously

PHImageRequestOptions *option = [PHImageRequestOptions new];
option.synchronous = YES;

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
        //this block will be called synchronously
}];

Donc, votre bloc sera appelé avant de terminer votre méthode

Bonne chance!

75
Tony

Par défaut, requestImageForAsset fonctionne comme asynchrone. Ainsi, dans votre méthode, l'instruction return sera exécutée avant même que l'image soit récupérée. Donc, ma suggestion est au lieu de renvoyer le imageView, passez le imageView en ce que vous devez remplir l'image:

func swipeView(swipeView: SwipeView!, viewForItemAtIndex index: Int, reusingView view: UIView!, yourImageView: UIImageView)
{
    let asset: PHAsset = self.photosAsset[index] as PHAsset

    var imageView: UIImageView! = yourImageView;

    let screenSize: CGSize = UIScreen.mainScreen().bounds.size
    let targetSize = CGSizeMake(screenSize.width, screenSize.height)


    var options = PHImageRequestOptions()
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact

    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
        imageView.image = result;
    })
}

Remarque:

Une autre option est que vous pouvez déclencher une notification avec l'image du résultat de resultHandler. Mais je préfère la méthode mentionnée ci-dessus.

Reportez-vous à PHImageManager pour plus d'informations.

4
Midhun MP

Le bloc resultHandler: contient un dictionnaire d'informations qui peut contenir une valeur booléenne pour la clé PHImageResultIsDegradedKey, qui indique si l'image résultante est un substitut de qualité médiocre à l'image demandée. 

Voici ce que dit la documentation:

PHImageResultIsDegradedKey: Une valeur booléenne indiquant si le fichier l’image résultante est un substitut de qualité médiocre à l’image demandée . (NSNumber)

Si la valeur est OUI, le paramètre result de votre bloc resultHandler contient un image de basse qualité car Photos ne pouvait pas encore fournir un image de meilleure qualité. En fonction de vos paramètres dans le Objet PHImageRequestOptions que vous avez fourni avec la demande, Les photos peuvent appeler à nouveau votre bloc de gestionnaire de résultats pour fournir un image de meilleure qualité.

4
O Fenômeno

Consultez la documentation Apple pour cette méthode ici. En ce qu'ils disent: 

Photos peut appeler votre bloc de gestionnaire de résultats pour une demande asynchrone plus d'une fois. Photos appelle d’abord le bloc pour obtenir une qualité inférieure image pouvant être affichée temporairement pendant qu'elle prépare un image de haute qualité. (Si des données d'image de mauvaise qualité sont immédiatement disponibles, le premier appel peut avoir lieu avant le retour de la méthode.)

Cela peut prendre du temps, dans votre cas, pour récupérer une image de taille originale. Sinon, votre code me semble correct.

1
Mrunal

Vous ne devriez pas réécrire imageView à l'intérieur du bloc, définissez-y simplement l'image et tout devrait fonctionner comme prévu. Pour éviter d'afficher deux images, vous pouvez vérifier la taille de l'image avant de l'attribuer. 

var imageView =  UIImageView()
...
...
        PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
                println("huhuhuh")
                println(result.size)
                println(info)
                if result.size.width > 1000 &&  result.size.height > 1000 { // add any size you want 
                     imageView.setImage(result)
                }
            })
1
sage444

Utilisez les options ci-dessous, Swift 3.0

publi var imageRequestOptions: PHImageRequestOptions{
let options = PHImageRequestOptions()
options.version = .current
options.resizeMode = .exact
options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true
options.isSynchronous = true
return options}
0
Hiren Panchal

essayez cela fonctionnera aussi pour asynchrone.

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
    if ([info objectForKey:@"PHImageFileURLKey"]) {
      //your code
    }
}];
0
vaibby