iphone - 多线程在获取照片时使用 GCD

标签 iphone ios multithreading asynchronous grand-central-dispatch

如果在 UITableView 中找到,我必须从地址簿中获取联系人并在每个联系人旁边显示照片。

我使用 ABContactsHelper 库获取所有联系人,然后使用 GCD block 异步获取 UITableView 中可见行的照片。

我提到了一个 Apple 示例代码,它等待 UITableView 完成滚动,获取可见的 NSIndexPath 并创建线程来获取照片。到目前为止,我的问题有两个。

首先,如果用户滚动、停止、滚动并停止并执行多次,则会生成太多线程来获取照片,这会降低应用程序的速度。

其次,当线程返回以在缓存中设置照片以及 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];
            }
        }
    }
}

最佳答案

对于这种功能,我会选择 NSOperation 和 NSOperationQueue,它们构建在 GCD 之上,但它为您提供了取消操作的机会。您可以检查哪些操作不再可见并取消它们。通过这种方式,您可以控制引用“离开”。
我还看到另一个可能导致“问题”的问题,您似乎正在 NSMutableDictionary 中缓存图像,不是吗?或者你在使用 NSCache?如果它是一个 NScache 就很好,但是大多数可变对象“自然”不是线程安全的
提高队列的优先级:-)

关于iphone - 多线程在获取照片时使用 GCD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16330825/

相关文章:

iphone - 关于 iPhone 应用程序包对于 App Store 的合理大小的问题。存储内存!

ios - 如何在 iOS 上使用透明的 fontello 图标

c# - 在 C# 中为循环中的方法创建线程

objective-c - 我在哪个 GCD 队列(主队列或非主队列)上运行?

objective-c - 是否在单独的线程中显示UIAlertView会停止在主线程中进行处理?

iphone - UIImageView 动画在 UITableView 中停止

iOS 应用程序库目录 <uid> 总是会更改

iphone - 如何自定义 iOS 警报 View ?

ios - Firebase 的新手和 swift。无法将 Firebase 连接到 Xcode

iphone - 存储大量音频资源