nsmyself
nsmyself

Reputation: 3565

Why does this UIWebView to UIImage code render a blank image?

I know this is pretty common, but I just wanted to know why this very simple code doesn't work.

I have a breakpoint in the NSLog line inside the webViewDidFinishLoad method and I'm inspecting the resulting UIImage (using quick look). The result is a blank image where the UIWebView should be (and the black background I placed there for debugging purposes).

#import "KIViewController.h"

@interface KIViewController ()

@end

@implementation KIViewController

-(void)webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"start");
}

-(void)webViewDidFinishLoad:(UIWebView *)webView {

    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    NSLog(@"webview did finish load");

}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIWebView *wv = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,640,200)];
    wv.delegate = self;

    NSString *url=@"http://www.google.com";
    NSURL *nsurl=[NSURL URLWithString:url];
    NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
    [wv loadRequest:nsrequest];
    self.view.backgroundColor = [UIColor blackColor];
    [self.view addSubview:wv];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Why is this happening and how can I prevent it?

Upvotes: 0

Views: 986

Answers (1)

Tcharni
Tcharni

Reputation: 644

I've had this problem too once. There is a slight delay between when the delegate function, webViewDidFinishLoad: is called, and when the webView content is drawn to the screen. The content exists and is stored in the webView. Just that it's not rendered on-screen. I don't know why this occurs, but I guess it is because the rendering process of a webView takes longer than the average UIKit object (owing to vector graphics).

In my case, I needed to adjust the size of the frame of the webView based on the loaded content. And so, I did all my frame adjustments on the main thread and called the screenshot function from a background thread. Something like:

dispatch_async(dispatch_get_main_queue(), ^{
    /*
     do some adjustments here
    */

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
        [view.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage * screenshot = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    });
});

As far as thread safety is concerned, I found this in another answer:

Core Graphics and Core Animation being low-level APIs, are generally thread safe. However, the same rules about access still apply: Any work must not be accessed by more than one thread at the same time, else drawing will fail and your app will crash. I would be wary (but not afraid) of UIImage, as UIKit objects aren't just not thread safe, they're basically ticking time bombs in background threads, and will happily dive straight off a cliff into Exception Land for no good reason. However, because UIImage is just a CGImage wrapper, again ,most drawing is thread safe.

Hope this helps.

Upvotes: 1

Related Questions