iOS: Webview causes flicking while navigating to another controller - iphone

I use webview in my UIVIewController and load the local HTML file in it using following method.
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]];
If I put this method in ViewDidLoad, I can see white flicking while navigating to my controller that doesn't look good.
I tried putting this method in ViewWillAppear like below. I am using webViewLoaded flag to make sure that webview has been loaded then only show the current view else it waits but it is going in infinite loop of waiting!
- (void)viewWillAppear:(BOOL)animated {
webViewLoaded = NO;
webView.scalesPageToFit = allowZoom;
webView.dataDetectorTypes = UIDataDetectorTypeNone;
webView.delegate = self;
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]];
int count = 0;
while(webViewLoaded == NO)
{
NSLog(#"Waiting...");
[NSThread sleepForTimeInterval:0.1];
if(count++ > 10) break;
}
}
- (void)webViewDidFinishLoad:(UIWebView *)localwebView {
webViewLoaded = YES;
}
I have also tried the same thing in ViewDidLoad but still its going in infinite loop.
Please note that webViewLoaded is "volatile BOOL" but the webview delegate method is not getting called. Not sure what's going on!
Could anyone please help me to fix this. Thanks.

First : You're blocking your main thread and not giving WebView any chance to finish loading. Never block your main thread.
Second : There are two UIWebView delegate methods : webViewDidFinishLoad and webView:didFailLoadWithError: - make sure to listen to both.
If you're trying to wait until WebView completes loading and only show your controller afterwards - use delegation or blocks. Please note that this is not a proper way of doing things - i'm just modifying your example to make it work :
child controller (with WebView) :
-(void)startLoadingWithParent:(id)_parent {
self.parent = _parent;
NSURL * url = [[NSBundle mainBundle] URLForResource:#"resource" withExtension:#"html"];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
[parent showMe:self];
}
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[parent showError:error];
}
master controller :
-(void)doSomething {
SecondController * ctrl; /// secondController should be created AND has its view loaded at this point
/// ctrl = [SecondController new];
/// ctrl.view;
[ctrl startLoadingWithParent:self];
/// show user that we're doing something - display activity indicator or something
}
-(void)showMe:(UIViewController*)me {
[self.navigationController pushViewControllerAnimated:me];
}

Try using [NSURL fileURLWithPath:filePath]

use Following code for
[self performSelectorInBackground:#selector(webViewLoaded) withObject:nil];
so that it will not affect your UI

Related

Press a Button and open a URL in another ViewController

I am trying to learn Xcode by making a simple app.
But I been looking on the net for hours (days) and I cant figure it out how I make a button that open a UIWebView in another ViewController :S
first let me show you some code that I have ready:
I have a few Buttons om my main Storyboard that each are title some country codes like UK, CA and DK.
When I press one of those Buttons I have an IBAction like this:
- (IBAction)ButtonPressed:(UIButton *)sender {
// Google button pressed
NSURL* allURLS;
if([sender.titleLabel.text isEqualToString:#"DK"]) {
// Create URL obj
allURLS = [NSURL URLWithString:#"http://google.dk"];
}else if([sender.titleLabel.text isEqualToString:#"US"])
{
allURLS = [NSURL URLWithString:#"http://google.com"];
}else if([sender.titleLabel.text isEqualToString:#"CA"])
{
allURLS = [NSURL URLWithString:#"http://google.ca"];
}
NSURLRequest* req = [NSURLRequest requestWithURL:allURLS];
[myWebView loadRequest:req];
}
How do I make this open UIWebview on my other Viewcontroller named myWebView?
please help a lost man :D
Well, you've firstViewController already designed and coded, now you've to create secondViewController with a UIWebView binded in IB it self, also it have a setter NSString variable like strUrl that you need to pass at the time of pushing or presenting secondViewController, and assign it to UIWebView in viewDidLoad of secondViewController. See my answer about how to pass a NSString? Also UIWebView has its delegates method (What's delegate & datasource methods? - Apple Doc) Which you can use to handle URL request.
These are the delegate of UIWebView, if you'll going to use it, you need to give UIWebView delegate to self.
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
firstViewController.m
- (IBAction)ButtonPressed:(UIButton *)sender {
NSURL* allURLS;
//get your URL
secondViewControlelr *secondView=[[secondViewControlelr alloc]init];
second.urlToLoad=allURLS;
[self.navigationController pushViewController:secondView animated:YES];
}
secondViewControlelr.h
//declare url and set property
NSURL *urlToLoad;
secondViewControlelr.m
- (void)viewDidLoad
{
myWebView=[[UIWebView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview:myWebView];
NSURLRequest *urlReq=[NSURLRequest requestWithURL:self.urlToLoad cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:10];
[myWebView loadRequest:urlReq];
}

UIWebView getting crashed

I have a UIWebView which will load the documents. All the supported documents mentioned for webview it is working. But sometimes , the UIWebView is getting crashed whenever I move back and forth quickly. I mean I am clicking back and opening file again and again. If I do so , my app is getting crashed.
Any idea why this is happening ?? It is working cool for video,audio and txt files, but weird crashing for the Office docs and numbers,pages documents.
Please help me out !!
-(void) backBtnPressed
{
[_webView stopLoading];
if ([_webView superview])
{
[_webView removeFromSuperview];
self.navigationItem.rightBarButtonItem = nil;
}
}
- (void) loadFile:(NSString*)filePath
{
NSURL* url = [NSURL fileURLWithPath:filePath];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
[webView setScalesPageToFit:YES];
}
Set the delegate property of the webview to nil in the dealloc of your controller
If you are moving from one view controller to another, do the following
[webView stopLoading];
webView.delegate = nil;
Implement this and chk what error you are getting.
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog("Error=%s",error);
}
The problem is solved.Setting the UIWebView to nil and loading the request again in the WebView. But now only at most worst case the App is getting crashed.
Try this :
-(void)viewWillDisappear:(BOOL)animated
{
if([webView isLoading])
{
[webView stopLoading];
}
}
Just adding this here on the off chance that someone else is making the same beginner mistake:
Remember that webView.delegate is a weak reference. If you set it to something else than self your delegate may get destroyed if there are no other references to it, which will cause all kinds of crashes.
Try to do the following. It works for me.
[webView stopLoading];
[webView release];
webView = nil;
webView.delegate = nil;

Block main thread until UIWebView finishes loading

I'm trying to block the main thread until a UIWebView finishes loading, but calling [NSThread sleepForTimeInterval:] after calling [UIWebView loadRequest:] makes the loading never complete: The webViewDidFinishLoad delegate is called after the sleep finishes.
Why is this happening? and How can I block the main thread?
I'm calling loadPage from [ViewController willRotateToInterfaceOrientation:], what I'm trying to do is to prevent the iOS interface to rotate until the webview with the other orientation is loaded.
- (void)loadPage {
UIWebView* webview2 = [[UIWebView alloc] initWithFrame:rect];
webview2.delegate = self;
NSString* htmlPath = ..... ; // Path to local html file
NSURL *newURL = [[[NSURL alloc] initFileURLWithPath: htmlPath] autorelease];
NSURLRequest *newURLRequest = [[[NSURLRequest alloc] initWithURL: newURL] autorelease];
[webview2 loadRequest:newURLRequest];
[NSThread sleepForTimeInterval:10.0f]; // Why this blocks the uiwebview thread ??
[self.view addSubview:webview2];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"Finished loading!");
}
I think you're trying to solve the wrong problem.
You don't want to block the main thread. Firstly, the entire UI is drawn on the main thread, so it will appear as though your app has hung. Secondly, a UIWebView is part of the UI (which is probably why what you're doing doesn't work).
So, what to do?
Have a look at the following method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
When you start loading your page you can return NO from this method. When it's finished loading you can return values normally. UIWebView has a delegate that tells you the status.
Have a look at the class reference for NSURLRequest, there is a sync method in there.
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

UIwebview loader on iphone

this code works fine , its show activityIndicator loading and hide after loading
but lets say if its on loading stage and then i go back then my apps quit , so how to avoid this
if i go back quickly withiut site fully loaded then it quits ( i think activityIndicator is culprit)
**
- (void)webViewDidStartLoad:(UIWebView *)webView {
[activityIndicator startAnimating];
// myLabel.hidden = FALSE;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
activityIndicator.hidesWhenStopped=TRUE;
//myLabel.hidden = TRUE;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
self.title=#"KKH Website";
[super viewDidLoad];
NSURL *requestUrl = [NSURL URLWithString:#"http://www./index.html"];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:requestUrl];
[aWw loadRequest:requestObj];
}
**
updates
if i link uiwebview delegate to fileowner then its creating isuee , but i need delegate also since i want to show loading
i forgot to release my webview :(
[aWw release];
now its fixed

Iphone: controlling text with delay problem with UIWebView

I've opted to use UIWebView so I can control the layout of text I've got contained in a local html document in my bundle. I want the text to display within a UIWebView I've got contained within my view. So the text isn't the whole view, just part of it.
Everything runs fine, but when the web page loads I get a blank screen for a second before the text appears. This looks really bad. can anyone give me an example of how to stop this happening? I'm assuming I have to somehow hide the web view until it has fully loaded? Could someone one tell me how to do this?
At the moment I'm calling my code through the viewDidLoad like this:
[myUIWebView loadRequest: [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"localwebpage" ofType:#"html"] isDirectory:NO]]];
Any help is much appreciated. I've read round a few forums and not seen a good answer to this question, and it seems like it recurs a lot as an issue for beginners like myself.
Thanks for taking the time to read this post!
UPDATED info
Thanks for your response. The suggestions below solves the problem but creates a new one for me as now when my view loads it is totally hidden until I click on my toggle switch. to understand this it's maybe most helpful if I post all my code. Before this though let me explain the setup of my view. I've got a standard view within which I've also got two web views, one on top of the other. each web view contains different text with different styling. the user flicks between views using a toggle switch, which hides/reveals the web views. I'm using the web views because I want to control the style/layout of the text. Below is my full .m code, I can't figure out where it's going wrong. My web views are called oxford & harvard I'm sure its something to do with how/when I'm hiding/revealing views. I've played around with this but can't seem to get it right. Maybe my approach is wrong. A bit of advice ironing this out would be really appreciated:
#implementation ReferenceViewController
#synthesize oxford;
#synthesize harvard;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
[oxford loadRequest: [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Oxford" ofType:#"html"] isDirectory:NO]]];
[harvard loadRequest: [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Harvard" ofType:#"html"] isDirectory:NO]]];
[oxford setHidden:YES];
[harvard setHidden:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if([webView hidden]) {
[oxford setHidden:NO];
[harvard setHidden:NO];
}
}
//Toggle controls for toggle switch in UIView to swap between webviews
- (IBAction)toggleControls:(id)sender {
if ([sender selectedSegmentIndex] == kSwitchesSegmentIndex)
{
oxford.hidden = NO;
harvard.hidden = YES;
}
else
{
oxford.hidden = YES;
harvard.hidden = NO;
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[oxford release];
[harvard release];
}
#end
Sure, in your UIViewController's designated initializer, set the hidden property of the UIWebView instance to YES:
[webView setHidden:YES];
Then, implement the UIWebViewDelegate method - (void)webViewDidFinishLoad:, and perform an if check inside the method like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if([webView hidden]) {
[webView setHidden:NO];
}
}
Also, don't forget to specify that your class conforms to the UIWebViewDelegate protocol:
#interface YourViewController : UIViewController <UIWebViewDelegate> {...}