什么';iPhone上异步图像缓存的最佳方法是什么?

什么';iPhone上异步图像缓存的最佳方法是什么?,iphone,image,caching,asynchronous,abaddressbook,Iphone,Image,Caching,Asynchronous,Abaddressbook,我正在创建一个iPhone应用程序,它将从Web API中提取数据,包括电子邮件地址。我想在表格单元格中显示与每个电子邮件地址相关联的图像,因此我在地址簿中搜索图像,如果电子邮件地址不在地址簿中,则返回默认设置。这很有效,但我有几个顾虑: 性能:据报道,我找到的通过电子邮件地址(或电话号码)查找通讯录记录的方法如下。这样做的原因是,必须迭代每个地址簿记录,对于每个有图像的记录,迭代所有电子邮件地址以找到匹配项。当然,对于大型通讯簿来说,这可能很耗时 表格单元格:所以我想我应该收集所有需要查找图

我正在创建一个iPhone应用程序,它将从Web API中提取数据,包括电子邮件地址。我想在表格单元格中显示与每个电子邮件地址相关联的图像,因此我在地址簿中搜索图像,如果电子邮件地址不在地址簿中,则返回默认设置。这很有效,但我有几个顾虑:

  • 性能:据报道,我找到的通过电子邮件地址(或电话号码)查找通讯录记录的方法如下。这样做的原因是,必须迭代每个地址簿记录,对于每个有图像的记录,迭代所有电子邮件地址以找到匹配项。当然,对于大型通讯簿来说,这可能很耗时

  • 表格单元格:所以我想我应该收集所有需要查找图像的电子邮件地址,并立即找到它们。通过这种方式,我只对所有地址重复阅读这本书一次。但这对表格单元格不起作用,因为每个单元格对应一个电子邮件地址。我要么在显示任何单元格之前收集所有图像(可能会很慢),要么让每个单元格在加载图像时查找每个图像(甚至更慢,因为我需要在书中反复查找每个电子邮件地址的匹配项)

  • 异步查找:所以我想我应该批量查找它们,但使用异步方法。对于在AddressBook中找到的每个图像,我会在应用程序沙箱中保存一个缩略图。然后,每个单元格都可以引用这个文件,如果它不存在,则显示默认值(因为它不在书中或尚未找到)。如果稍后在异步查找中找到该图像,则下次需要显示该图像时,它会突然出现。这可能适用于定期重新生成图像(例如,当地址簿中的图像发生更改时)。但是,对于我的应用程序的任何给定实例,图像可能在一段时间内不会显示

  • 异步表格单元格查找:理想情况下,我会在下载图像后使用类似于更新表格单元格的内容。但要使其工作,我必须在每个单元格显示时以及在沙箱中缺少缓存图标时为其派生一个
    NSInvocationOperation
    作业。但是,我们又回到了低效地遍历每个地址簿的整个地址簿,如果您刚刚下载了一大堆新的电子邮件地址,那么这些地址可能会很多

所以我的问题是:其他人是如何做到这一点的?我在摆弄Tweetie2,它看起来像是异步更新显示的表格单元格。我假设它正在为它需要的每个图像发送一个单独的HTTP请求。如果是这样的话,我想通过电子邮件地址搜索本地通讯簿的效率不会降低,所以这也许是最好的方法?只是不用担心与搜索通讯簿相关的性能问题

如果是这样,在沙箱中保存缩略图是否是缓存的最佳方法?如果我想创建一个新的作业,用地址簿中的任何更改更新所有缩略图,比如说每天更新一次,那么最好的方法是什么


你们其他人是如何解决这类问题的?建议将不胜感激

我将使用您列出的最后一种方法(异步表格单元格查找),但仅查找当前显示记录的图像。我重载UIScrollViewDelegate方法以查明用户何时停止滚动,然后才开始请求当前可见单元格

类似这样的内容(这是从我在网上找到的一个教程中稍微修改的,我现在找不到了,很抱歉没有引用作者):

-(void)加载可访问单元格的内容
{
NSArray*单元格=[self.table visibleCells];
[细胞保留];
对于(int i=0;i<[单元计数];i++)
{ 
//遍历数组中的每个单元格,并在其响应时调用其loadContent方法。
AddressRecordTableCell*addressTableCell=(AddressRecordTableCell*)[[cells objectAtIndex:i]retain];
[addressTableCell loadImage];
[细胞释放];
addressTableCell=nil;
}
[细胞释放];
}
-(void)ScrollViewDiEndDecelling:(UIScrollView*)scrollView;
{
//方法在减速停止时调用。
//将可见单元格传递给单元格加载功能。如果可能,请更改
//滚动视图到指向表单元格的指针,以避免编译器警告
[可视单元格的自加载内容];
}
-(void)ScrollViewDiEndDraging:(UIScrollView*)scrollView将减速:(BOOL)减速;
{
如果(!减速)
{
[可视单元格的自加载内容];
}
}

一旦你知道什么地址记录是当前可见的,只需搜索这些(5-7条记录可能)将是闪电般的快。抓取图像后,只需将其缓存在字典中,以便以后不必重新请求图像。

您似乎试图在UITableView中实现惰性图像加载。 苹果有一个很好的例子,我在这里引用:

无论您使用何种策略来实际缓存图像,如果可能的话,每次您获得一批电子邮件地址时,我只会通过地址簿数据一次。(是的,我会异步执行此操作。)

创建一个NSMutableDictionary,作为搜索结果的内存缓存。使用下载的每个电子邮件地址作为密钥初始化此词典,并使用sentinel作为该密钥的值(例如
[NSNull null]

接下来,遍历地址簿中的每个ABRecordRef,调用
ABRecordCopyValue(record,kabbersonemailproperty)
并循环遍历返回的每个ABMultiValue中的结果。如果任何电子邮件地址都是缓存中的密钥,请将
- (void)loadContentForVisibleCells
{
    NSArray *cells = [self.table visibleCells];
    [cells retain];
    for (int i = 0; i < [cells count]; i++) 
    { 
        // Go through each cell in the array and call its loadContent method if it responds to it.
        AddressRecordTableCell *addressTableCell = (AddressRecordTableCell *)[[cells objectAtIndex: i] retain];
        [addressTableCell loadImage];
        [addressTableCell release];
        addressTableCell = nil;
    }
    [cells release];
}


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; 
{
    // Method is called when the decelerating comes to a stop.
    // Pass visible cells to the cell loading function. If possible change 
    // scrollView to a pointer to your table cell to avoid compiler warnings
    [self loadContentForVisibleCells]; 
}


- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
    if (!decelerate) 
    {
       [self loadContentForVisibleCells]; 
    }
}