后台线程上的drawViewHierarchyInRect

时间:2014-07-01 16:00:35

标签: ios multithreading uiview screenshot

我正在尝试在后台线程上进行一些“屏幕外渲染”,以更新我正在创建的类似设计器的应用的预览。

我在NSOperationQueue派生的队列中使用renderInContext来完成此操作,但请注意它很慢。

所以,我开始使用drawViewHierarchyInRect,效果很好而且速度更快。但是,我注意到当这个方法以b / g运行时,我的UI完全阻塞。

如果我在主线上这样做......

    UIView *preview = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
    preview.backgroundColor = [UIColor redColor];

    UIGraphicsBeginImageContextWithOptions(preview.bounds.size, NO, 0.0);

    BOOL ok = [preview drawViewHierarchyInRect:preview.bounds afterScreenUpdates:YES];

    UIImage *img = nil;

    if( ok )
    {
        img = UIGraphicsGetImageFromCurrentImageContext();
    }

    UIGraphicsEndImageContext();

......一切正常。

但是,如果我(比如说)发送这个......

if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW) == 0) 
{
    dispatch_async(renderQueue, ^{
        // capture
        UIView *preview = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
        preview.backgroundColor = [UIColor redColor];

        UIGraphicsBeginImageContextWithOptions(preview.bounds.size, NO, 0.0);

        BOOL ok = [preview drawViewHierarchyInRect:preview.bounds afterScreenUpdates:YES];

        UIImage *img = nil;

        if( ok )
        {
            img = UIGraphicsGetImageFromCurrentImageContext();
        }

        UIGraphicsEndImageContext();
}
        dispatch_semaphore_signal(semaphore);
    });

...我的用户界面在执行完毕后冻结了。

'ok'返回YES,所以似乎一切正常。

如果我将afterUpdates设置为NO,则'ok'为NO(失败),但UI仍然会响应。

使用drawViewHierarchyInRect除主线程以外的任何东西都有限制吗?

2 个答案:

答案 0 :(得分:2)

UIKit对象只能在主线程上操作。 Apple的UIKit documentation提到了这个说法

  

在大多数情况下,只能从应用程序的主线程中使用UIKit类。这是   特别适用于从UIResponder派生的类或涉及的类   以任何方式操纵您的应用程序的用户界面。

答案 1 :(得分:0)

您是从主线程调用上述dispatch_async吗?我的理论是你用[preview drawViewHierarchyInRect:preview.bounds afterScreenUpdates:YES];调用YES需要在主线程上执行一些代码,但主线程在信号量上被阻塞。您可能想要做的是偶尔屈服于主线​​程,以便drawViewHierarchyInRect可以完成。

__block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_async(renderQueue, ^{
    /// your code here
    /// ...
   BOOL ok = [preview drawViewHierarchyInRect:preview.bounds afterScreenUpdates:YES];
    .....
    dispatch_semaphore_signal(sema);
});

while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}