What is expected performance of drawViewHierarchyI

2020-07-27 03:30发布

问题:

After browsing through all the relevant question on SO, I understand drawViewHierarchyInRect is supposed to be much faster than renderInContext, yet this is not what I am seeing.

Here is my snapshot function with time profiling:

- (UIImage *)screenshot
{
    UIScreen *mainScreen = [UIScreen mainScreen];
    CGSize imageSize = mainScreen.bounds.size;
    if (&UIGraphicsBeginImageContextWithOptions != NULL) {
        UIGraphicsBeginImageContextWithOptions(imageSize, NO, 1);
    } else {
        UIGraphicsBeginImageContext(imageSize);
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    NSArray *windows = [[UIApplication sharedApplication] windows];
    for (UIWindow *window in windows) {
        if (![window respondsToSelector:@selector(screen)] || window.screen == mainScreen) {
            NSDate *methodStart = [NSDate date];

//            [window.layer renderInContext:context];
            [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:NO];

            NSDate *methodFinish = [NSDate date];
            NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
            NSLog(@"executionTime = %f", executionTime);
        }
    }

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}

Tests were done on iPad Air with IOS 9.0 As a test app, I am using UIKitCatalog application https://developer.apple.com/library/ios/samplecode/UICatalog/Introduction/Intro.html

The app shows 2 windows:

<UIWindow: 0x134e4d8f0; frame = (0 0; 768 1024); gestureRecognizers = <NSArray: 0x134e27740>; layer = <UIWindowLayer: 0x134e4d130>>,
<UITextEffectsWindow: 0x134e6a3a0; frame = (0 0; 768 1024); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x134e6aba0>>

Using drawViewHierarchyInRect results in 0.078s on any of the two windows renderInContext results in 0.045s on the main window and some smaller (0.000028s) time on the UITextEffectsWindow.

  1. Why is drawViewHierarchyInRect slower than renderInContext, isn't it supposed to be faster

  2. Both (78ms, 45ms) are unacceptable for recording video of the screen with any decent frame rate. Seems like something is very wrong, it should be much faster.

  3. [window.layer renderInContext...] results in screenshots which are messy and inaccurate, I've tried [window.layer.presentationLayer renderInContext...], yet this results in application crashes and I can't find the reason.

I would appreciate any help with this, all I am trying to do is record a video of the screen at the highest frame rate possible and so far the results I am getting do not make sense or I might be doing something very wrong.

Thanks

回答1:

You asked:

  1. Why is drawViewHierarchyInRect slower than renderInContext, isn't it supposed to be faster?

It depends entirely upon what you're capturing. For example, capturing a view with a bunch of simple UIView subviews, I see no appreciable difference. When when capturing a view with complex UIImageView (e.g. a very high resolution image), I find that drawViewHierarchyInRect can be roughly 10 times as fast in extreme situations. I find that latter performance difference comparable to what Apple claimed in Implementing Engaging UI in iOS where their example included a bunch of image views.

I infer from those diagnostics that drawViewHierarchyInRect is optimized for screen snapshots with UIImageView objects. So while it might be highly optimized for a particular scenario, I'm not entirely surprised that there might exist scenarios, for which it wasn't intended, that don't yield the same results.

  1. Both (78ms, 45ms) are unacceptable for recording video of the screen with any decent frame rate. Seems like something is very wrong, it should be much faster.

These weren't designed for video capture, so I'm not sure what you mean by "something is very wrong." Why do you say "it should be much faster"?

  1. [window.layer renderInContext...] results in screenshots which are messy and inaccurate ...

You should edit your question to include screen snapshot to show us what you mean.

... I've tried [window.layer.presentationLayer renderInContext...], yet this results in application crashes and I can't find the reason.

The presentationLayer method is for getting a copy of the current presentation state (generally used for inquiring mid-animation), but it's not a layer with which you generally interact.