2016-08-12 1 views
0

En utilisant l'API Facebook Graph, j'ai récupéré une URL de chaîne pour une image de profil 200x200 que je souhaite afficher dans un UIImageView. Je suis capable de le faire avec succès, mais je remarque que cela peut prendre jusqu'à 10 secondes pour que l'image s'affiche sur l'écran. Quelqu'un peut-il me donner quelques conseils (sans jeu de mots) sur la façon de l'optimiser?L'image basse résolution est trop longue à charger

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 

    NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) -> 
     Void in 
     self.profilePictureImageView.image = UIImage(data: data!) 
     self.profilePictureImageView.layer.cornerRadius = self.profilePictureImageView.frame.size.width/2; 
     self.profilePictureImageView.clipsToBounds  = true 

     dispatch_async(dispatch_get_main_queue(), {() -> Void in 
      self.view.addSubview(self.profilePictureImageView) 
     }) 

    }).resume() 
} 
+0

Vous essayez peut-être d'ajouter la sous-vue en dehors de l'appel asynchrone, puis de simplement définir l'image de la sous-vue dans le bloc d'achèvement? – brandonscript

Répondre

3

Vous devez passer tous les appels UIView (donc tout ce que vous définissez sur le UIImageView) sur le thread principal comme UIKit pour la plupart ne sont pas thread-safe. Vous pouvez instancier le UIImage sur le fil de fond que pour l'optimisation des performances, alors essayez ceci:

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 

    let url = NSURL(string: self.profilePictureUrl)! 

    NSURLSession.sharedSession().dataTaskWithURL(
     url, 
     completionHandler: { [weak self] (data, response, error) -> Void in 
      guard let strongSelf = self else { return } 

      // create the UIImage on the background thread 
      let image = UIImage(data: data!) 

      // then jump to the main thread to modify your UIImageView 
      dispatch_async(dispatch_get_main_queue(), { [weak self]() -> Void in 
       guard let strongSelf = self else { return } 

       let profilePictureImageView = strongSelf.profilePictureImageView 

       profilePictureImageView.image = image 
       profilePictureImageView.layer.cornerRadius = profilePictureImageView.frame.size.width/2; 
       profilePictureImageView.clipsToBounds = true 

       strongSelf.view.addSubview(profilePictureImageView) 
      }) 
     } 
    ).resume() 
} 

Notez aussi que j'ai weak -ified vos références à self. Il n'y a aucune garantie que l'utilisateur n'a pas rejeté le contrôleur de vue qui initie ce code au moment où les routines d'achèvement sont appelées, donc vous voulez vous assurer que vous ne gardez pas une référence forte à self. Cela permet au contrôleur de vue de se désaffecter si l'utilisateur le rejette et que les routines d'achèvement reviennent rapidement sans faire de travail inutile.

+0

Merci beaucoup pour toutes ces améliorations. Je suis curieux - avez-vous intentionnellement créé deux références à 'strongSelf'? Je demande seulement parce que Xcode donne un avertissement pour l'une de ces déclarations. – AlexanderHart

+0

Oui, vous aurez besoin de deux références à 'strongSelf' car chaque callback risque de provoquer un saut de thread. Si Xcode se plaint, vous devrez changer l'un des noms de variables, par exemple faites le 'strongSelfInner' interne. – par

0

Ce code est illégal:

NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: self.profilePictureUrl)!, completionHandler: { (data, response, error) -> 
    Void in 
    self.profilePictureImageView.image = UIImage(data: data!) 

Stop! vous définissez l'image d'un UIImageView sur un fil d'arrière-plan. Non non Non. UIKit n'est pas thread-safe. Vous devez entrer dans le thread principal pour le faire. (Vous finissez par entrer dans le fil principal de votre code, mais vous le faites trop tard.)