Search code examples
iosobjective-casynchronousuiwebviewobjective-c-blocks

iOS how can I add a completion block to UIWebView loadRequest:?


I'm working with a UIWebView and am already using webViewDidFinishLoad: method with an optional block that gets executed after loading complete:

    -(void)webViewDidFinishLoad:(UIWebView *)webView
    {
        [super webViewDidFinishLoad:webView];

//... bunch of other code        

        if(self.webViewFinishLoadBlock != nil)
        {
            self.webViewFinishLoadBlock();
        }
    }

Now I'm working with an even more complicated sequence of loading pages and redirects that makes the logic above not sufficient. I don't want to register myself as a delegate of dummyWebView and have to juggle multiple completion blocks stored in my view controller's properties:

    dummyWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
    [dummyWebView loadRequest:[NSURLRequest requestWithURL:logoutURL]];
//Ideally here I would know when dummyWebView finishes loading, because there's some code I want to execute once it is done

My question is:

Is there some kind of third party framework that would allow me to use loadRequest:withCompletion: to simplify writing callback code?


Solution

  • You can just:

    • Subclass UIWebView with a property to hold the webViewDidFinish completion block;

    • Make sure it specifies its delegate;

    • Implement the webViewDidFinish much like you wrote it (though I'd suggest the block return both the web view as well as the NSError object, if any); and

    • Implement the webView:didFailLoadWithError:, too.

    Thus:

    //  MyWebView.h
    
    #import <UIKit/UIKit.h>
    
    typedef void(^WebViewFinishLoadBlock)(UIWebView *, NSError *);
    
    @interface MyWebView : UIWebView
    
    @property(nonatomic, copy) WebViewFinishLoadBlock webViewFinishLoadBlock;
    
    - (void)loadRequest:(NSURLRequest *)request withCompletionHandler:(WebViewFinishLoadBlock)completionHandler;
    
    @end
    

    And

    //  MyWebView.m
    
    #import "MyWebView.h"
    
    @interface MyWebView () <UIWebViewDelegate>
    @end
    
    @implementation MyWebView
    
    - (void)loadRequest:(NSURLRequest *)request withCompletionHandler:(WebViewFinishLoadBlock)completionHandler
    {
        self.delegate = self;
        self.webViewFinishLoadBlock = completionHandler;
    
        [self loadRequest:request];
    }
    
    #pragma mark - UIWebViewDelegate
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
        if (self.webViewFinishLoadBlock) {
            self.webViewFinishLoadBlock(webView, nil);
            self.webViewFinishLoadBlock = nil;
        }
    }
    
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
    {
        if (self.webViewFinishLoadBlock) {
            self.webViewFinishLoadBlock(webView, error);
            self.webViewFinishLoadBlock = nil;
        }
    }
    
    @end
    

    And then:

    MyWebView *webView = [[MyWebView alloc] init];
    webView.frame = self.view.bounds;
    [self.view addSubview:webView];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [webView loadRequest:request withCompletionHandler:^(UIWebView *webView, NSError *error) {
        if (error) {
            NSLog(@"failed: %@", error);
        } else {
            NSLog(@"succeeded");
        }
    }];