在可重用表格单元格中使用NSCache和dispatch_async的正确方法是什么?
我一直在寻找一个明确的方法来做到这一点,并没有发现任何地方,将举一个例子,并解释得很好。 我希望你能帮助我。
这是我正在使用的代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"NewsCell"; NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; // Configure the cell... NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row]; cell.newsTitle.text = item.title; NSCache *cache = [_cachedImages objectAtIndex:indexPath.row]; [cache setName:@"image"]; [cache setCountLimit:50]; UIImage *currentImage = [cache objectForKey:@"image"]; if (currentImage) { NSLog(@"Cached Image Found"); cell.imageView.image = currentImage; }else { NSLog(@"No Cached Image"); cell.newsImage.image = nil; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) { NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.image]]; dispatch_async(dispatch_get_main_queue(), ^(void) { cell.newsImage.image = [UIImage imageWithData:imageData]; [cache setValue:[UIImage imageWithData:imageData] forKey:@"image"]; NSLog(@"Record String = %@",[cache objectForKey:@"image"]); }); }); } return cell; }
caching返回为零。
Nitin回答了如何使用caching相当好的问题。 问题是,最初的问题和Nitin的答案都有一个问题,就是你正在使用GCD,它(a)不能控制并发请求的数量; 和(b)被派遣的块不可取消。 此外,你正在使用dataWithContentsOfURL
,这是不可取消。
请参阅WWDC 2012video带有块,GCD和XPC的asynchronousdevise模式 ,第7节“分离控制和数据stream”,约48分钟进入video,讨论为何存在问题,即如果用户快速向下滚动列表到第100个项目,所有其他99个请求都将排队。 在极端的情况下,可以使用所有可用的工作线程。 而iOS只允许五个并发的networking请求,所以没有必要使用所有这些线程(并且如果一些调度的块启动了由于超过五个而不能启动的请求,一些networking请求将开始失败)。
因此,除了当前使用cachingasynchronous执行networking请求的方法之外,还应该:
-
使用操作队列,它允许您(a)约束并发请求的数量; (b)开放取消操作的能力;
-
也使用可取消的
NSURLSession
。 你可以自己做或者使用像AFNetworking或SDWebImage这样的库。 -
当单元格被重用时,取消前一个单元格的任何未决请求(如果有的话)。
这可以做到,我们可以告诉你如何正确地做到这一点,但它是很多的代码。 最好的方法是使用caching的许多UIImageView
类别之一,但也处理所有这些其他问题。 SDWebImage的UIImageView
类别相当不错。 这大大简化了你的代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"NewsCell"; // BTW, stay with your standard single cellIdentifier NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier indexPath:indexPath]; NewsItem *item = newsItemsArray[indexPath.row]; cell.newsTitle.text = item.title; [cell.imageView sd_setImageWithURL:[NSURL URLWithString:item.image] placeholderImage:[UIImage imageNamed:@"placeholder.png"]]; return cell; }
可能是你做了一些错误的设置NSCache
每个图像相同的密钥
[cache setValue:[UIImage imageWithData:imageData] forKey:@"image"];
使用这个而不是上面设置的ForKey作为一个图像pathitem.image和使用setObject而不是setVlaue : –
[self.imageCache setObject:image forKey:item.image];
尝试这个代码示例: –
在.h类中: –
@property (nonatomic, strong) NSCache *imageCache;
在.m类中: –
- (void)viewDidLoad { [super viewDidLoad]; self.imageCache = [[NSCache alloc] init]; // the rest of your viewDidLoad } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"cell"; NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row]; cell.newsTitle.text = item.title; UIImage *cachedImage = [self.imageCache objectForKey:item.image];; if (cachedImage) { cell.imageView.image = cachedImage; } else { cell.imageView.image = [UIImage imageNamed:@"blankthumbnail.png"]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.image]]; UIImage *image = nil; if (imageData) image = [UIImage imageWithData:imageData]; if (image) { [self.imageCache setObject:image forKey:item.image]; } dispatch_async(dispatch_get_main_queue(), ^{ UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath]; if (updateCell) cell.imageView.image = [UIImage imageWithData:imageData]; NSLog(@"Record String = %@",[cache objectForKey:@"image"]); }); }); } return cell; }
- NSURLConnection sendAsynchronousRequest无法从闭包中获取variables
- IOS我如何asynchronous下载和caching图像和video在我的应用程序中使用
- 如何包装一个asynchronous方法,它将一个块转换为同步的目标c
- 在加载数据之前完成所有asynchronous请求?
- 等待asynchronous请求结果
- NSOperationQueue内部的NSOperation中的asynchronouscallback从来没有被调用过
- 完成处理程序和返回值
- 使用dispatch_async或performSelectorOnMainThread在主线程上执行UI更改?
- 如何asynchronous加载UITableViewcell图像,以便滚动不滞后