I created a NSOperationQueue
to download images (from Twitter for Cell):
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperationWithBlock:^{
NSString *ImagesUrl = [[NSString alloc]initWithFormat:@"http://api.twitter.com/1/users/profile_image/%@",[[status objectForKey:@"user"]objectForKey:@"screen_name"]];;
NSURL *imageurl = [NSURL URLWithString:ImagesUrl];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageurl]];
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
if (img.size.width == 0 || [ImagesUrl isEqualToString:@"<null>"]) {
[statusCell.imageCellTL setFrame:CGRectZero];
statusCell.imageCellTL.image = [UIImage imageNamed:@"Placeholder"] ;
}else
[statusCell.imageCellTL setImage:img];
this working fine, but when it appears to move the scroll and view the images are still loading, and they are changing several times until you get a picture.
And I do not like the diagnosis Profile of Time, so I wanted to somehow make this NSOperationQueue
in Background
is also possible to show how to make a "Imagecache" no need to download an image already downloaded.
**(Status = NSDictionary of Twitter Timeline).
editing::(All Cell)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Celulatime";
UITableViewCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ( [Cell isKindOfClass:[TimeLineCell class]] ) {
TimeLineCell *statusCell = (TimeLineCell *) Cell;
status = [self.dataSource objectAtIndex:indexPath.row];
statusCell.TextCellTL.text = [status objectForKey:@"text"];
statusCell.NomeCellTL.text = [status valueForKeyPath:@"user.name"];
statusCell.UserCellTL.text = [NSString stringWithFormat:@"@%@", [status valueForKeyPath:@"user.screen_name"]];
NSDate *created_at = [status valueForKey:@"created_at"];
if ( [created_at isKindOfClass:[NSDate class] ] ) {
NSTimeInterval timeInterval = [created_at timeIntervalSinceNow];
statusCell.timeCellTL.text = [self timeIntervalStringOf:timeInterval];
} else if ( [created_at isKindOfClass:[NSString class]] ) {
NSDate *date = [self.twitterDateFormatter dateFromString: (NSString *) created_at];
NSTimeInterval timeInterval = [date timeIntervalSinceNow];
statusCell.timeCellTL.text = [self timeIntervalStringOf:timeInterval];
}
NSString *imageUrlString = [[NSString alloc]initWithFormat:@"http://api.twitter.com/1/users/profile_image/%@",[[status objectForKey:@"user"]objectForKey:@"screen_name"]];;
UIImage *imageFromCache = [self.imageCache objectForKey:imageUrlString];
if (imageFromCache) {
statusCell.imageCellTL.image = imageFromCache;
[statusCell.imageCellTL setFrame:CGRectMake(9, 6, 40, 40)];
}
else
{
statusCell.imageCellTL.image = [UIImage imageNamed:@"TweHitLogo57"];
[statusCell.imageCellTL setFrame:CGRectZero];
[self.imageluckluck addOperationWithBlock:^{
NSURL *imageurl = [NSURL URLWithString:imageUrlString];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageurl]];
if (img != nil) {
[self.imageCache setObject:img forKey:imageUrlString];
// now update UI in main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
TimeLineCell *updateCell = (TimeLineCell *)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell) {
[updateCell.imageCellTL setFrame:CGRectMake(9, 6, 40, 40)];
[updateCell.imageCellTL setImage:img];
}
}];
}
}];
}
}
return Cell;
}
A good example from Ray Wenderlich : http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
It also having cancel function to cancel operation in case user press cancel button.
A couple of observations:
You should probably define a
NSOperationQueue
in your class and initialize it inviewDidLoad
(as well as aNSCache
) and add operations to that queue, rather than creating a newNSOperationQueue
for every image. Also, many servers limit the number of concurrent requests they'll support from each client, so make sure to setmaxConcurrentOperationCount
accordingly.Your
tableView:cellForRowAtIndexPath:
should make (a) initialize theimage
before starting the asynchronous image load (so you don't see the old image from the reused cell there); and (b) make sure the cell is still visible before you update it:No special handling of
UIApplicationDidReceiveMemoryWarningNotification
is needed because althoughNSCache
does not respond to this memory warning, it does automatically evict its objects as memory becomes low.I haven't tested the above code, but hopefully you get the idea. This is the typical pattern. Your original code had a check for
[ImagesUrl isEqualToString:@"<null>"]
, which I don't see how could ever be the case, but if you need some additional logic besides just myif (img != nil) ...
, then adjust that line accordingly.