Katya
Katya

Reputation: 300

Crash after setting WebView Delegate

I have developed the webView in method viewDidLoad in ViewController

UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
id <UIWebViewDelegate> delegate =[[MyDelegate alloc] init];
webView.delegate = delegate;
NSError *error;
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];

NSString *htmlContent = [[NSString alloc] initWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:&error];
[webView loadHTMLString:htmlContent baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];

[self.view addSubview:webView];

I set the delegate on instance of class MyDelegate.

In MyDelegate Class:

#import <UIKit/UIKit.h>

 @interface MyDelegate : NSObject <UIWebViewDelegate>

 @end



#import "MyDelegate.h"

 @implementation MyDelegate

 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 

    return YES;

 }
 @end

But app my crash during start the loasding. If I not load html content, but url ('google.com' for example) crash happens.

When I comment this 'webView.delegate = delegate;' crash doesn't happens.

I know that I can use this in ViewController.h:

@interface ViewController : UIViewController<UIWebViewDelegate>

and this in viewDidLoad:

webView.delegate = self;

but I need use other class as delegate (not ViewController), but webview must be located in ViewController.

How I can make this? Help me!

Upvotes: 3

Views: 656

Answers (4)

Russian
Russian

Reputation: 1306

I'm posting a separate answer because I think there's a need to provide explicit Objective-C solution, since OP might miss David GONZALEZ's answer because it's in Swift, although he absolutely nailed it.

The problem is that by the time web view calls its delegate, that delegate has been deallocated. So the solution would be to add property of MyDelegate type to ViewController private extension declaration:

@interface ViewController ()
@property (nonatomic, strong) MyDelegate* webViewDelegate;
@end

And then to store MyDelegate instance created in -viewDidLoadin that property:

...
id <UIWebViewDelegate> delegate =[[MyDelegate alloc] init];
webView.delegate = delegate;
self. webViewDelegate = delegate;
...

Upvotes: 0

David GONZALEZ
David GONZALEZ

Reputation: 11

Let me point to the root cause. UIWebView delegate attribute is a weak reference ("unowned(unsafe)" in Swift source code), which means its memory can be freed at any time.

So to solve this, you have to keep a reference into your controller as a class attribute.

Example of solution tested successfully in Swift:

class MyUIViewController : UIViewController{
    let leftDelegate:MyWebViewDelegate = MyWebViewDelegate()
    ...
}

Upvotes: 1

Mohd Khalil Ur Rehman
Mohd Khalil Ur Rehman

Reputation: 169

In your ViewController itself you can implement UIWebViewDelegate.

-(void)viewDidLoad {

[super viewDidLoad];

UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
webView.delegate = self;

NSError *error;

NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];

NSString *htmlContent= [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:&error];
[webView loadHTMLString:htmlContent baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];

[self.view addSubview:webView];

}

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

return YES;

}

Upvotes: 0

Saurabh Jain
Saurabh Jain

Reputation: 1698

- (void)viewDidLoad {
    [super viewDidLoad];
    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    id<UIWebView> delegate =(id)self;
    webView.delegate = delegate;
    NSError *error;
    NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];

    NSString *htmlContent= [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:&error];
    [webView loadHTMLString:htmlContent baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];

    [self.view addSubview:webView];
}

MyDelegate.h

#import <UIKit/UIKit.h>

@protocol UIWebView <UIWebViewDelegate>
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;


@end
@interface MyDelegate : NSObject
@end

Upvotes: 0

Related Questions