rs/SDWebImage — pull request #311 by sebreh (2013-02-26 12:17:04+00:00)
Title: Detect cancelled parent operation in download operation callback

I noticed that when scrolling fast in a UITableView containing cells with a UIButton, some of the completion handlers where called for operations that should have been cancelled as the table view scrolls. This happens when there are multiple requests to download an image at a certain URL. This caused the image to change even though the previous operation should have been cancelled.

After some debugging I figured out that the _SDWebImageCombinedOperation_ instance associated with the each UIButton was indeed correctly cancelled (in _prepareForReuse_ of the cell), but the completion block was called when the child _SDWebImageDownloaderOperation_ finished.

This occurs because _SDWebImageCombinedOperation_ only dispatches a _SDWebImageDownloaderOperation_ for the first download request of a particular image URL, but it stores the callback for all subsequent requests.

Hence, calling the _cancel_ method [here](https://github.com/rs/SDWebImage/blob/master/SDWebImage/SDWebImageManager.m#L163) on an _SDWebImageCombinedOperation_ instance that was not the first to request that particular image URL, will not cancel the download operation because the _subOperation_ variable will be nil. And when the download finishes, its callback will be called even though the parent _SDWebImageCombinedOperation_ was cancelled.

This bug occurs because there is not a one-to-one mapping of _SDWebImageCombinedOperation_ to _SDWebImageDownloaderOperation_.

So I added a check in the download operation callback that captures a weak reference to the initiating _SDWebImageCombinedOperation_. This creates a one-to-one an association between the callback and the top level _SDWebImageCombinedOperation_ associated with the UIButton.

Let me know if this doesn't make sense or I am missing something.