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?
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]];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With