iOS iOS - 2 months ago 15
iOS Question

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
)

Answer

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