iOS
iOS

Reputation: 3626

Do not execute the block if task is cancelled

I have MainViewController -> ThumbnailViewController -> ImageFullScreenViewController. As their name implies, I have a main screen from which I go to a screen which shows collection of images and on selecting an image, I open the image in full screen.

In ThumbnailViewController, I download images as follows

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)
        }
    }

In viewDidLoad() I call getImages(). In viewWillDisappear() of ThumbnailViewController, I cancel the ongoing tasks.

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()
                }
            }
        }
    }
}

The problem is, when I open ThumbnailViewController and immediately go back and if I open ThumbnailViewController immediately, I can see two copies of same image in some cases (rarely, but reproducible).

On investigation, I found that, cancelling the NSURLSessionDataTask in viewWillDisappear does cancel the task only, but not the completion block (which is the behavior). In some rare cases, the completion block is executed for the previous NSURLSessionDataTask thereby ending mixing with the response of the new NSURLSessionDataTask.

How could I handle this?

Note: galleryImages is a singleton property which I am reusing in ImageFullScreenViewController (UIPageViewController)

Upvotes: 2

Views: 404

Answers (1)

Yury
Yury

Reputation: 6114

Firstly, you should take care about release ThumbnailViewController object. Declare capture list with weak self, and it will, by additional, remove your issue in 99% cases (if you are not retaining self in some other places), though your model still not perfect with that 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)
    }
}

Upvotes: 0

Related Questions