Search code examples
objective-cuiwebviewuiwebviewdelegate

UIWebView Delegate : webViewDidFinishLoad not being called


I try to load an array of UIWebView with delegate associated.

for (GDataXMLElement *post in array) {
    NSString *msg = [[[post elementsForName:@"message"] objectAtIndex:0] stringValue];
    UIWebView *web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
    web_view.delegate = self;
    [web_view loadHTMLString:msg baseURL:nil];
    NSLog(@"Msg: %@", msg);
}

where msg is some HTML codes reading from XML. XML is loaded properly (verified by the NSLog line). Then in my webViewDidFinishLoad::

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    CGRect frame = webView.frame;
    frame.size.height = 1;
    webView.frame = frame;
    CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
    frame.size = fittingSize;
    webView.frame = frame;
    NSLog(@"WebView Height: %.1f", webView.frame.size.height);

    [webviews addObject:webView];
}

I auto resize the web views and add them to a NSMutableArray called webviews. However, webViewDidFinishLoad is not called.

In the header .h file, the interface is defined as:

@interface ViewController : UIViewController<UIWebViewDelegate>

What did I miss? Is the web_view in the loop get disposed ?

p.s. It looks like a duplicate of this question, but it isn't.


Alternate Approach 1

Declared at .h:

@property (nonatomic, weak) NSMutableArray *webviews;

Then for implementation:

for (GDataXMLElement *post in array) {
    NSString *msg = [[[post elementsForName:@"message"] objectAtIndex:0] stringValue];
    UIWebView *web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
    web_view.delegate = self;
    [web_view loadHTMLString:msg baseURL:nil];
    NSLog(@"Msg: %@", msg);
    [self.webviews addObject:web_view];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    CGRect frame = webView.frame;
    frame.size.height = 1;
    webView.frame = frame;
    CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
    frame.size = fittingSize;
    webView.frame = frame;
    NSLog(@"WebView Height: %.1f", webView.frame.size.height);
}

Alternate Approach 2

Instead of instantiating UIWebView in for-loop, I put it in header file.

@interface ViewController : UIViewController<UIWebViewDelegate> {
    UIWebView *web_view;
}

Then change the for-loop:

for (GDataXMLElement *post in array) {
    NSString *msg = [[[post elementsForName:@"message"] objectAtIndex:0] stringValue];
    web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
    web_view.delegate = self;
    [web_view loadHTMLString:msg baseURL:nil];
    NSLog(@"Msg: %@", msg);
    [self.webviews addObject:web_view];
}

In this approach, only the delegate of last message gets called.


Summary & Highlights:

My objectives:

  1. Load all UIWebView with variable-size contents
  2. The web views should auto fit the size of contents ( without scrolling ); that's why webViewDidFinishLoad is required.
  3. Arrange the web views properly on current view ( or probably a UIScrollView ) in order to make it not overlapped.

Solution

  • Here is my final solution ( hope it is useful for others ):

    In Storyboard, I added a UIScrollView in the view controller, and link it with the IBOutlet.

    Header file:

    #import <UIKit/UIKit.h>
    #import "GDataXMLNode.h"
    
    @interface ViewController : UIViewController<UIWebViewDelegate> {
        IBOutlet UIScrollView *scroll_view;
    }
    @property (nonatomic, strong) UIWebView *web_view;
    
    @end
    

    Implementation file:

    float currentY;
    NSArray *array;
    int count;
    GDataXMLDocument *doc;
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        currentY = 0;
        count = 0;
        [self loadXML];
    }
    
    - (void)loadXML {
       // Some codes to load the XML contents into array variable
       [self loadWebView];
    }
    
    - (void)loadWebView {
        if(count < array.count) {
            GDataXMLElement *post = [array objectAtIndex:count];
            NSString *msg = [[[post elementsForName:@"message"] objectAtIndex:0] stringValue];
            count++;
            self.web_view = [[UIWebView alloc] initWithFrame:CGRectMake(10, currentY, 300, 1.0f)];
            self.web_view.delegate = self;
            [self.web_view setHidden:YES];
            [self.web_view loadHTMLString:msg baseURL:nil];
            [scroll_view addSubview:self.web_view];
        } else {
            // end the process
            [scroll_view setContentSize:CGSizeMake(320, currentY + 30)];
            return;
        }
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        CGRect frame = webView.frame;
        frame.size.height = 1;
        webView.frame = frame;
        CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
        frame.size = fittingSize;
        webView.frame = frame;
        [webView setHidden:NO];
    
        currentY += webView.frame.size.height + 20.0f; // 20.0f is spaces between posts
    
        NSLog(@"WebView Height: %.1f", webView.frame.size.height);
        [self loadWebView];
    }