Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 在可重用的表单元中使用NSCache和dispatch\u async的正确方法是什么?_Iphone_Ios_Asynchronous_Nscache - Fatal编程技术网

Iphone 在可重用的表单元中使用NSCache和dispatch\u async的正确方法是什么?

Iphone 在可重用的表单元中使用NSCache和dispatch\u async的正确方法是什么?,iphone,ios,asynchronous,nscache,Iphone,Ios,Asynchronous,Nscache,我一直在寻找一个明确的方法来做到这一点,但没有找到任何地方可以给出一个例子,并解释得很好。我希望你能帮助我 以下是我正在使用的代码: - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"NewsCell"; NewsCell *cell = [tableView de

我一直在寻找一个明确的方法来做到这一点,但没有找到任何地方可以给出一个例子,并解释得很好。我希望你能帮助我

以下是我正在使用的代码:

- (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;
}

缓存为我返回零。

可能是您做错了,您为
NSCache

[cache setValue:[UIImage imageWithData:imageData] forKey:@"image"];
使用此选项而不是上面的set-ForKey作为Imagepath项。image并使用setObject而不是setVlaue:-

[self.imageCache setObject:image forKey:item.image];
请尝试以下代码示例:-

in.h类:-

@property (nonatomic, strong) NSCache *imageCache;
- (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;
}
in.m类:-

@property (nonatomic, strong) NSCache *imageCache;
- (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;
}

尼廷回答了关于如何很好地使用缓存的问题。问题是,原始问题和Nitin的答案都存在一个问题,即使用GCD时,(a)不能控制并发请求的数量;和(b)调度的块是不可取消的。此外,您正在使用
dataWithContentsOfURL
,这是不可取消的

请参阅WWDC 2012视频,第7节,“单独的控制和数据流”,视频开始约48分钟,了解这一问题的原因,即如果用户快速向下滚动列表至第100项,所有其他99个请求都将排队。在极端情况下,您可能会耗尽所有可用的辅助线程。而且iOS只允许五个并发网络请求,因此没有必要用尽所有线程(如果一些已调度的块启动由于超过五个而无法启动的请求,则您的一些网络请求将开始失败)

因此,除了当前异步执行网络请求和使用缓存的方法外,您还应该:

  • 使用操作队列,它允许您(a)限制并发请求的数量;以及(b)开放取消操作的能力

  • 也使用可取消的
    nsursession
    。您可以自己完成,也可以使用AFNetworking或SDWebImage之类的库

  • 重新使用单元格时,取消前一个单元格的所有挂起请求(如果有)

  • 这是可以做到的,我们可以向您展示如何正确地做到这一点,但这需要大量的代码。最好的方法是使用多个
    UIImageView
    类别中的一个,它们进行缓存,但也处理所有其他问题。的
    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;
    }
    

    如果在加载图像时重复使用单元格,会发生什么情况?您似乎在单元格中设置了错误的映像。是的,我还希望缓存objectAtIndex:indexath.row,以便映像与表行一样属于缓存中的相应插槽。现在,当您在加载时滚动图片时,它会将错误的图片加载到错误的行中。我希望答案能反映这一点,因为我使用的是可重复使用的细胞。谢谢你的回答。@Kendallhlhelmstettergelner因为Nitin聪明地在最后的
    dispatch\u async
    中调用了
    cellforrowatinexpath
    ,它确保了当你将单元格重新用于表的另一行时,旧的调度任务不会不适当地更新错误的行。因此,这个实现优雅地让旧的请求完成,并为下一个单元将新任务分派到后台。这是一个很好的实现(尽管在连接速度慢或图像较大的情况下,一个稍微更优雅的解决方案是取消旧请求或以某种方式延迟它们)。尽管我同意您可能希望在某个时候添加取消请求的选项。@Nitin Gohel感谢您的回答。我无法获得对我的代码所做的更改(根据您的回答),这导致了令人满意的应用程序更改,这无疑是我的错。不过,我会选择Rob的答案作为我问题的最佳解决方案和答案。你可能想看看SDWebImage项目,它已经解决了所有问题。你能提供一个链接吗?非常好的解释,我也学到了正确的东西,因为它给了我们非常好的答案。事实上,我只是根据NSCache的问题给出了答案。但是是的,Sdwebimage和AFnetworking也非常适合这样做task@Rob有没有比我如何提问更好的方法来更好地理解你的答案。谢谢你的回答,我觉得它很有用。@Cedric不,我认为你的问题很好。你问了“我如何缓存”,你提供了足够的上下文让我们不喊“提供代码!”或“你尝试了什么?!”。哈哈,只是在这种情况下,应该使用GCD的假设并不是最优的。这是苹果建议使用操作队列的案例之一。而
    UIImageView
    类别只不过更进一步,让您远离基于
    NSOperation
    的代码的杂草。但是,如果在我的回答中有什么你不明白的地方(尤其是在看了视频之后),请告诉我们。