2016-09-16 1 views
2

J'ai MainViewController ->ThumbnailViewController ->ImageFullScreenViewController. Comme leur nom l'indique, j'ai un écran principal à partir duquel je vais sur un écran qui montre une collection d'images et en sélectionnant une image, j'ouvre l'image en plein écran.N'exécute pas le bloc si la tâche est annulée

En ThumbnailViewController, je télécharger des images comme suit

private func getImages() { 
     self.galleryImages.removeAll() 
     for url in urls { 
      let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in 

       // errors are handled 

       if let image = UIImage(data: data) { 
        self.galleryImages.append(image!) 
       } 
      } 
      task.resume() 
      requests.append(task) 
     } 
    } 

En viewDidLoad() j'appelle getImages(). Dans viewWillDisappear() de ThumbnailViewController, j'annule les tâches en cours.

override func viewWillDisappear(animated: Bool) { 
    super.viewWillDisappear(animated) 
    if isMovingFromParentViewController() { 
     if requests.count > 0 { 
      for request in requests { 
       if request is NSURLSessionDataTask { 
        let task = request as! NSURLSessionDataTask 
        task.cancel() 
       } 
      } 
     } 
    } 
} 

Le problème est, quand j'ouvre ThumbnailViewController et immédiatement revenir en arrière et si j'ouvre ThumbnailViewController immédiatement, je peux voir deux exemplaires de même image dans certains cas (rarement, mais reproductible).

Lors de l'enquête, j'ai constaté que l'annulation de NSURLSessionDataTask dans viewWillDisappear annule la tâche uniquement, mais pas le bloc d'achèvement (qui est le comportement). Dans de rares cas, le bloc d'achèvement est exécuté pour le précédent NSURLSessionDataTask, terminant ainsi le mélange avec la réponse du nouveau NSURLSessionDataTask.

Comment puis-je gérer cela?

Note: galleryImages est une propriété singleton que je réutilisez dans ImageFullScreenViewController (UIPageViewController)

+0

Sur un côté facile :) pourquoi ne pas simplement vérifier si l'image existe avant de l'ajouter à galleryImages en utilisant quelque chose comme galleryImages.contains (image) {...} –

+0

Est-ce que la propriété compilée 'galleryImages' ou y a-t-il des observateurs? S'il vous plaît, montrez la déclaration. Il n'y a rien d'étrange, cette tâche parfois déjà sur le chemin de finir avec l'achèvement; étrange est comment il est capable de mélanger l'image reçue avec un tableau d'images dans * nouvelle * instance de 'ThumbnailViewController'. Cela peut arriver si 'galleryImages' est partagé d'une manière ou d'une autre. –

+0

Désolé. J'aurais dû le mentionner. 'galleryImages' est un singleton. Je l'ai fait singleton, parce que, je réutilise le même tableau pour 'UIPageViewController' dans' ImageFullScreenViewController' – iOS

Répondre

0

Tout d'abord, vous devez prendre soin de libération objet ThumbnailViewController. Déclarer la liste de capture avec weak self, et il sera, par plus, retirez votre question dans le cas de 99% (si vous ne retenez pas self dans d'autres endroits), bien que votre modèle toujours pas parfait avec cette Singletone

private func getImages() { 
    self.galleryImages.removeAll() 
    for url in urls { 
     let task = NSURLSession.sharedSession().dataTaskWithURL(url) { [weak self] (data, response, error) in 

      // errors are handled 
      // replace self. with self?. 

      if let image = UIImage(data: data) { 
       self?.galleryImages.append(image!) 
      } 
     } 
     task.resume() 
     requests.append(task) 
    } 
} 
+1

Réviser le modèle comme suggéré a résolu le problème. Je vous remercie! – iOS

+0

À moins que j'aie mal compris votre suggestion, même celle-ci n'est pas garantie de fonctionner correctement si un seul contrôleur de vue démarre accidentellement deux extractions en même temps. IMO, une approche plus robuste serait de A. remplacer galerieImages avec un nouveau tableau dans removeAll, B. stocker que dans une nouvelle variable * en dehors du bloc, C. capturer cette variable à l'intérieur du bloc au lieu de self.galleryImages, D. exécutez les tripes du bloc sur votre thread principal de sorte que vous n'aurez pas plusieurs threads avec un seul tableau mutable. De cette façon, chaque ensemble de requêtes remplit toujours un nouveau tableau et seul le dernier est utilisé. – dgatwood

+0

@dgatwood vous avez raison. Je viens de souligner une question importante sur le code existant, et à un modèle imparfait; J'ai décidé que suggérer un autre modèle concret serait trop large –