线程问题在ios 7上的表现不同

时间:2013-09-23 19:17:18

标签: iphone ios

我在github上使用这个Project,它是一个图像选择器。 我不得不做一个非常小的改动,因为ios7让你的专辑中的预览图像再次显示但是现在当你离开选择器然后回到它时所选择的照片(2/5)重置为0 / 5即使我选择了照片。我该如何解决这个问题?

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)似乎永远需要更新ui,即使用dispatch_async(dispatch_get_main_queue()来重新加载ui。当我注释掉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 个答案:

答案 0 :(得分:6)

AGIPCGridItemUIView的子类。 不能在后台线程上使用UIKit对象。

确保您需要后台线程,如果这样做,请将繁重的任务放到后台。创建UIView不应该是这种情况。

此外,建议不要使用PRIORITY_LOW使用简单PRIORITY_DEFAULT

编辑:如果您好奇为什么它确实在iOS 6上运行:那是UIKit的实现细节。它仍然是错的,但不知怎的做了你所期望的。

答案 1 :(得分:0)

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

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

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

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

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

UITableViewCell load images and reused cells

但即使我将呼叫包裹在dispatch_async(dispatch_get_main_queue()...)内,它也无法正常工作。

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

答案 2 :(得分:0)

全局调度队列是共享资源。 DISPATCH_QUEUE_PRIORITY_LOW任务在队列中以更高优先级运行的每个其他任务运行之后运行。如果队列中提交了大量以更高优先级提交的块,则DISPATCH_QUEUE_PRIORITY_LOW任务可能无法运行很长时间!

Concurreny Programming Guide以及libdispatch man pages

中记录了这一点

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

答案 3 :(得分:0)

我强调了iMartin的答案“AGIPCGridItem是UIView的子类。不能在后台线程上使用UIKit对象。”他得到了它。

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

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