问题
I have a table view that includes several feed cells that each have a few images a piece. I'm loading in the images like this:
[timeLineCell.avatar setImageWithURL:[NSURL URLWithString:[feedAccount accountAvatarUrl]] placeholderImage:avatarPlaceholderImage options:SDWebImageRetryFailed];
This works fine, but on slow connections the operations tend to just climb instead of removing old operations for the same images. That is -- if I scroll down and back up through the same cells, it adds the same images into the operation queue for a second, third, fourth, etc time.
I'm also attempting to remove images from the download queue when the cell gets reused like this in cellForRow:
- (void)prepareForReuse {
[super prepareForReuse];
[self.avatar cancelCurrentImageLoad];
}
But it seems like the operation doesn't match anything in the operation queue in SDWebImage's methods, so it doesn't actually cancel anything. If I run cancelAll on the shared manager it works, but it's obviously not ideal.
I'm aware I'm only showing one image on this cell, but I have commented out everything except for this image loading and the problem persists. It also persists if I comment out the avatar image and allow a different image (loaded similarly) to download instead.
Anyone have any tips on this?
P.S. I've tried changing the options from SDWebImageRetryFailed
to other things including no options at all, but it made no difference.
P.P.S. I'm using the latest version of SDWebImage available on CocoaPods (3.4).
回答1:
To solve this problem, I actually edited the SDWebImage framework a little bit.
First, I added the following method to SDWebImageManager
:
- (void)cancelOperation:(id<SDWebImageOperation>)operation {
@synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}
}
Then, I modified the - (void)cancel
method on SDWebImageCombinedOperation
:
- (void)cancel
{
self.cancelled = YES;
[[SDWebImageManager sharedManager] cancelOperation:self];
if (self.cacheOperation)
{
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock)
{
self.cancelBlock();
self.cancelBlock = nil;
}
}
This didn't completely get rid of the problem of extra operations being added on the queue, but the existing failed ones definitely get cleared out much faster, and as such the problem winds up not being an issue anymore. I'm assuming it appears there are more operations being added in the queue, but that's because the existing ones haven't checked their isCancelled
flags yet.
回答2:
I had this issue as well for a long time. I don't really know why this strategy doesn't work because it seems like it really should. I fixed the issue by switching to another API method from the same framework. Instead of using the shorthand UIImageView category method I switched to downloadWithURL:options:progress:completed instead.
This is what I ended up with in my UITableViewCell class:
@interface MyTableViewCell ()
@property (nonatomic, weak) id <SDWebImageOperation> imageOperation;
@end
@implementation MyTableViewCell
- (void)prepareForReuse {
[super prepareForReuse];
if (self.imageOperation) {
[self.imageOperation cancel];
}
self.imageOperation = nil;
[self.imageView setImage:self.placeholderImage];
}
- (void)configure {
SDWebImageManager *manager = [SDWebImageManager sharedManager];
self.imageOperation = [manager downloadWithURL:self.imageURL
options:SDWebImageRetryFailed
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
if (image) {
[self.imageView setImage:image];
}
}];
}
@end
来源:https://stackoverflow.com/questions/18727165/sdwebimage-operations-not-being-canceled