我创建了一个 NSOperationQueue
来下载图像(来自 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];
这工作正常,但是当它似乎移动滚动并查看图像时,图像仍在加载,并且它们会多次更改,直到您获得图片。
而且我不喜欢时间的诊断配置文件,所以我想以某种方式在后台制作这个
NSOperationQueue
还可以展示如何制作“Imagecache”而无需下载已下载的图像。
**(状态 = Twitter 时间线的 NSDictionary)。
编辑::(所有单元格)
- (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;
}
最佳答案
几个观察:
NSOperationQueue
并在 viewDidLoad
(以及 NSCache
)中初始化它并向该队列添加操作,而不是为每个图像创建一个新的 NSOperationQueue
。另外,许多服务器限制了每个客户端支持的并发请求数,因此请确保相应地设置maxConcurrentOperationCount
。@interface ViewController ()
@property (nonatomic, strong) NSOperationQueue *imageOperationQueue;
@property (nonatomic, strong) NSCache *imageCache;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageOperationQueue = [[NSOperationQueue alloc]init];
self.imageOperationQueue.maxConcurrentOperationCount = 4;
self.imageCache = [[NSCache alloc] init];
}
// the rest of your implementation
@end
tableView:cellForRowAtIndexPath:
应该使 (a) 初始化 image
(因此您看不到那里重用单元格中的旧图像); (b) 在更新之前确保该单元格仍然可见: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: ...]; // set your frame accordingly
}
else
{
statusCell.imageCellTL.image = [UIImage imageNamed:@"Placeholder"];
[statusCell.imageCellTL setFrame:CGRectZero]; // not sure if you need this line, but you had it in your original code snippet, so I include it here
[self.imageOperationQueue addOperationWithBlock:^{
NSURL *imageurl = [NSURL URLWithString:imageUrlString];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageurl]];
if (img != nil) {
// update cache
[self.imageCache setObject:img forKey:imageUrlString];
// now update UI in main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// see if the cell is still visible ... it's possible the user has scrolled the cell so it's no longer visible, but the cell has been reused for another indexPath
TimeLineCell *updateCell = (TimeLineCell *)[tableView cellForRowAtIndexPath:indexPath];
// if so, update the image
if (updateCell) {
[updateCell.imageCellTL setFrame:...]; // I don't know what you want to set this to, but make sure to set it appropriately for your cell; usually I don't mess with the frame.
[updateCell.imageCellTL setImage:img];
}
}];
}
}];
}
UIApplicationDidReceiveMemoryWarningNotification
进行特殊处理,因为尽管 NSCache
不响应此内存警告,但它会在内存变低时自动驱逐其对象。 我还没有测试过上面的代码,但希望你能明白。这是典型的模式。您的原始代码检查了
[ImagesUrl isEqualToString:@"<null>"]
,我不知道怎么会是这种情况,但是如果除了我的 if (img != nil) ...
之外还需要一些其他逻辑,请相应地调整该行。关于ios - NSOperationqueue 背景,下载图片,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14444041/