Reputation: 73
I want to download image for each row in a table view, so I wrote a method to do this by using block.
I thought the indexPath and tableView may be not copied by the completion block, because they are used in an If-Statement. So I retain them before the completion block excute.
and the code is:
- (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *cachedImagesOfURLs = self.cachedImagesOfURLs;
UITableView *strongTableView = [tableView retain];
NSIndexPath *strongIndexPath = [indexPath retain];
[self.downloadManager downloadImageAtURL:imageURL
identifier:[self identifierForIndexPath:indexPath]
serial:serial
completion:^(UIImage *image) {
if (image) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[cachedImagesOfURLs setObject:image forKey:imageURL];
id cell = [strongTableView cellForRowAtIndexPath:strongIndexPath];
if ([cell respondsToSelector:@selector(didDownloadImage:withName:)]) {
[cell didDownloadImage:image withName:name];
}
}];
}
[strongTableView release];
[strongIndexPath release];
}];
}
But the result is, when completion block excute and try to create a block and run it in main thread, it crash. The debugger print "-[XXX cellForRowAtIndexPath:]: unrecognized selector sent to instance". I seems that tableView and indexPath are deallocated.
But I don't know why, I have tried to retain them. Can somebody tell me how to prevent this crash happend? thank you very much!
Upvotes: 3
Views: 224
Reputation: 20021
I think this is enough
- (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *cachedImagesOfURLs = self.cachedImagesOfURLs;
[self.downloadManager downloadImageAtURL:imageURL
identifier:[self identifierForIndexPath:indexPath]
serial:serial
completion:^(UIImage *image) {
if (image) {
[cachedImagesOfURLs setObject:image forKey:imageURL];
id cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell respondsToSelector:@selector(didDownloadImage:withName:)]) {
[cell didDownloadImage:image withName:name];
}
}
}];
}
Upvotes: 1
Reputation: 62686
Even less code. Not sure how the bits of code you refer to work, but from the names, I'd guess the following is sufficient:
- (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *cachedImagesOfURLs = self.cachedImagesOfURLs;
[self.downloadManager downloadImageAtURL:imageURL identifier:[self identifierForIndexPath:indexPath] serial:serial completion:^(UIImage *image) {
if (image) {
[cachedImagesOfURLs setObject:image forKey:imageURL];
id cell = [strongTableView cellForRowAtIndexPath:strongIndexPath];
if ([cell respondsToSelector:@selector(didDownloadImage:withName:)]) {
[cell didDownloadImage:image withName:name];
}
}
}];
}
Upvotes: 0