Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

drawViewHierarchyInRect on background thread

I'm trying to do some 'offscreen rendering' on a background thread to update a preview of a designer-like app I'm creating.

I've used renderInContext on an NSOperationQueue-derived queue to accomplish this but note it's slow.

So, I've started using drawViewHierarchyInRect which works great and is much faster. However, I've noticed that my UI completely blocks when this method is run in the b/g.

If I do this on the main thread...

    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();

...it all works OK.

However, if I (say) dispatch this...

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);
    });

...my UI freezes, totally after execution.

'ok' is returning YES, so all seems to be working.

If I set afterUpdates to NO, 'ok' is NO (failed), but the UI continues to be responsive.

Are there any limits on using drawViewHierarchyInRect an anything other than the main thread?

like image 875
Fittoburst Avatar asked Jul 01 '14 16:07

Fittoburst


1 Answers

Are you calling the above dispatch_async from the main thread? my theory here is that you've called [preview drawViewHierarchyInRect:preview.bounds afterScreenUpdates:YES]; with YES which needs to execute some code on the main thread, however the main thread is blocked on the semaphore. What you probably want to do, is yield to the main thread once in a while so that drawViewHierarchyInRect can complete.

__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]];
}
like image 178
Vijay Sharma Avatar answered Sep 22 '22 09:09

Vijay Sharma