i need to load from web/files some UIImages. I was searching and i found in other question this code:
if (![[NSFileManager defaultManager] fileExistsAtPa
You are loading image asynchronously, so during fast scrolling cells get reused faster then images are downloaded. One way to avoid loading a wrong image, would be to check if cell already got reused when image is loaded. Or cancel all requests in progress when you dequeue new cells.
I would also recommend to look at AFNetworking, as it contains helpful category for UIImageView
, so you can do something like this:
[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];
It also contains cancelImageRequestOperation
method, to cancel requests in progress. Then your code will look like this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else {
[cell.imageView cancelImageRequestOperation];
}
[cell.imageView setImageWithURL:[NSURL URLWithString:user.imageURL] placeholderImage:[UIImage imageNamed:@"xger86x.jpg"]];
I suspect the incorrect images you see are a result of you not setting your place holder image in the event of you having a local copy of an image but still retrieving the local copy asynchronously. Also In the code you appended for loading the local copy you use UIImage
a UIKit
component on a background thread.
Also interestingly you seem to be doing some kind of UIImage
caching. Adding the images to what I assume is an NSMutableArray
property named imageFriends
. But you seem to have commented out the cache add in the event you have a local copy of the file. Also your posted code never uses the cached UIImages
.
While 2 levels of caching seems a bit overboard if you wanted to do this you could do something like this:
UIImage *userImage = [self.imageFriends objectForKey:[NSNumber numberWithInt:user.userId]];
if (userImage) { // if the dictionary of images has it just display it
cell.imageView.image = userImage;
}
else {
cell.imageView.image = [UIImage imageNamed:@"xger86x.jpg"]; // set placeholder image
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:user.image];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = nil;
if (fileExists){
imageData = [NSData dataWithContentsOfFile:user.image];
}
else {
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:user.imageURL]];
[imageData writeToFile:user.image atomically:YES];
}
if (imageData){
dispatch_async(dispatch_get_main_queue(), ^{
// UIKit, which includes UIImage warns about not being thread safe
// So we switch to main thread to instantiate image
UIImage *image = [UIImage imageWithData:imageData];
[self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]];
UITableViewCell *lookedUpCell = [tableView cellForRowAtIndexPath:indexPath];
if (lookedUpCell){
lookedUpCell.imageView.image = image;
[lookedUpCell setNeedsLayout];
}
});
}
});
}
UIImage
s are part of UIKit
and not thread safe. But you can load the NSData
on another thread.