我必须从地址簿中提取联系人,并在UITableView
找到照片旁边的照片。
我使用ABContactsHelper
库获取所有联系人,然后使用GCD块异步获取UITableView
中可见行的照片。
我提到了Apple示例代码,它等待UITableView完成滚动,得到Visible NSIndexPath
s&创建了获取照片的线程。到目前为止,我的问题有两个。
首先,如果用户滚动,停止,滚动&停止并且做了很多次,生成的线程太多,无法获取使应用程序变慢的照片。
其次,当线程返回设置缓存中的照片以及UITableViewCell
时,UIImageView
的引用现在正被重用于UITableViewCell
中的另一条记录,因此照片当特定记录的线程返回时,它被置于错误的记录上,最终被正确的记录替换。
以下是cellForRowAtIndexPath
以及UITableView
停止滚动时使用的代码。
- (void)loadImagesLazilyForIndexPath:(NSIndexPath *)indexPath photo:(UIImageView *)photo contact:(ContactModel *)contact
{
if (!self.tableView.isDragging && !self.tableView.isDecelerating) {
UIImage *thePhoto = [self.imagesForContacts objectForKey:indexPath];
if (!thePhoto) {
// NSLog(@"Photo Not Found - Now Fetching %@", indexPath);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
@autoreleasepool {
UIImage *image = [[JMContactsManager sharedContactsManager] photoForContact:contact];
if (!image)
image = self.noProfilePhoto;
[self.imagesForContacts setObject:image forKey:indexPath];
dispatch_async(dispatch_get_main_queue(), ^{
// NSLog(@"Photo Fetched %@", indexPath);
@autoreleasepool {
NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
BOOL visible = [visiblePaths indexOfObjectPassingTest:^BOOL(NSIndexPath * ip, NSUInteger idx, BOOL *stop) {
if (ip.row == indexPath.row && ip.section == indexPath.section) {
*stop = YES;
return 1;
}
return 0;
}];
if (visible)
photo.image = [self.imagesForContacts objectForKey:indexPath];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
});
}
});
} else {
// NSLog(@"Photo Was Found %@", indexPath);
@autoreleasepool {
photo.image = [self.imagesForContacts objectForKey:indexPath];
}
}
}
}
答案 0 :(得分:1)
对于这种功能,我会使用NSOperation和NSOperationQueue,它们构建在GCD之上,但它为您提供了取消操作的机会。您可以检查哪些操作不再可见并取消它们。这样你可以控制参考“离开” 我还看到另一个可能导致“问题”的问题,似乎你在NSMutableDictionary中缓存图像,不是吗?或者您使用的是NSCache吗?如果它是一个NScache很好,但大多数可变对象都不是“自然”线程安全的 提升队列的优先级: - )
答案 1 :(得分:1)
如@Andrea所述,您应该使用NSOperationQueue,它可以让您取消排队的任务。 通过indexPath将图像缓存索引到表中并不健壮,因为给定元素的索引路径可能会发生变化(尽管可能不是在您的特定情况下)。您可以考虑通过ABRecord.uniqueId索引图像缓存。
在任何情况下,它都无法解决您的图像被设置为同一个单元格两次或更多的问题。发生这种情况是因为UITableView没有为每个项目分配视图,而是管理UITableCellViews池,每次都重复使用它。你可以做的是以下几点:
// Assuming your "ContactCellView" inherits from UITableCellView and has a contact property
// declared as follows: @property (retain) ABRecord *contact.
- (void) setContact:(ABRecord*)contact
{
_contact = contact;
__block UIImage *thePhoto = [self.imagesForContacts objectForKey:contact.uniqueId];
if (thePhoto == nil) {
_loadImageOp = [NSBlockOperation blockOperationWithBlock:^(void) {
// Keep a local reference to the contact because it might change on us at any time.
ABRecord *fetchContact = contact;
// Fetch the photo as you normally would
thePhoto = [[JMContactsManager sharedContactsManager] photoForContact:fetchContact];
if (thePhoto == nil)
thePhoto = self.noProfilePhoto;
// Only assign the photo if the contact has not changed in the mean time.
if (fetchContact == _contact)
_contactPhotoView.image = thePhoto;
}];
} else {
_contactPhotoView.image = thePhoto;
}
}