8

我正在使用来自 github 的这个项目,它是一个图像选择器。自 ios7 以来,我不得不进行一个非常小的更改,以使您的相册中的预览图像再次显示,但是现在当您离开选择器并返回其中时,选择的照片(2/5)甚至重置为 0/5虽然我选择了照片。我怎样才能解决这个问题?

即使重新加载其中的ui ,dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)似乎也需要永远更新ui 。dispatch_async(dispatch_get_main_queue()当我注释掉dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)图片时,图片会立即加载,但其他取决于队列的东西会被破坏。

这是我更改的代码片段,dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0) 我更改的代码已注释掉

AGIPCAssetsController.m:

- (void)loadAssets
{
    [self.assets removeAllObjects];

    __ag_weak AGIPCAssetsController *weakSelf = self;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

        __strong AGIPCAssetsController *strongSelf = weakSelf;

        @autoreleasepool {
            [strongSelf.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {

                if (result == nil) 
                {
                    return;
                }

                AGIPCGridItem *gridItem = [[AGIPCGridItem alloc] initWithImagePickerController:strongSelf.imagePickerController asset:result andDelegate:strongSelf];
                if ( strongSelf.imagePickerController.selection != nil && 
                    [strongSelf.imagePickerController.selection containsObject:result])
                {
                    gridItem.selected = YES;
                }
                [strongSelf.assets addObject:gridItem];
            }];
        }

        dispatch_async(dispatch_get_main_queue(), ^{

            [strongSelf reloadData];

        });

    });
    [strongSelf reloadData];

}
4

4 回答 4

6

AGIPCGridItem是 的子类UIView不要在后台线程上使用 UIKit 对象。

确保您需要后台线程,如果需要,请仅将繁重的任务置于后台。创建一个UIView不应该是这种情况。

此外,不建议使用PRIORITY_LOWuse simple PRIORITY_DEFAULT

编辑:如果你好奇为什么它在 iOS 6 上工作:那是 UIKit 的实现细节。它仍然是错误的,但不知何故做了你所期望的。

于 2013-10-08T09:58:50.793 回答
0

我在这段代码上花了很多时间,但找不到合适的解决方案。显然这个问题已经出现在 github 上,一位用户提供了修复:

https://github.com/arturgrigor/AGImagePickerController/issues/19

但显然他只是删除了所有在后台运行的块,所以我认为对于大量图像,性能会很差。

我的预感是,在 dispatch_async 块内运行调用某些 UIKit 函数的代码,因此行为基本上是未定义的。

例如,在我看来,AGIPGridItem.msetAsset中的函数在您发布的 dispatch_async 中被调用。它正在调用 UImage,虽然它在锁内,但它仍然应该在后台线程上执行,而所有 UIKit 代码都应该在主线程上执行。

UITableViewCell 加载图像和重用单元格

但是,即使我将调用包装在 a dispatch_async(dispatch_get_main_queue()...)中,它也不起作用。

似乎AGIPGridell.m中的调用[view removeFromSuperview];以某种方式负责,但删除它会产生内存泄漏的副作用(不足为奇)。 setItems

于 2013-10-05T13:09:58.563 回答
0

全局调度队列是共享资源。DISPATCH_QUEUE_PRIORITY_LOW任务在队列中具有更高优先级的所有其他任务运行之后运行。如果队列有很多以更高优先级提交的块,您的DISPATCH_QUEUE_PRIORITY_LOW任务可能不会运行很长时间!

这在Concurreny Programming Guide以及 libdispatch手册页中有记录

所以,基本上,其他更高优先级的任务让事情变得忙碌,而你的低优先级任务没有机会去。

于 2013-10-08T09:37:33.600 回答
0

我强调了 iMartin 的回答“AGIPCGridItem 是 UIView 的子类。不要在后台线程上使用 UIKit 对象。” 他明白了。

将 iOS6 移动到 7 时,我遇到了一个非常相似的问题。我在后台线程中调度了一个 ALAssets 请求。获取完成后,我将构造 UIImageView、UILabel 和包装器,然后将此对象发送到要呈现的主/前台线程。这在 iOS6 上运行良好,但在 7 上它没有绘制大约 20 秒。它有时会在 UI 事件(如触摸)之后绘制。

修复是在后台获取 ALAsset,将其发送到我创建图像视图的主线程等。现在就像一个魅力。

于 2013-10-11T21:17:43.203 回答