What's the best option for loading web content in a UIWebView? - iphone

In previous apps, I've loaded data into a UIWebView using 4 steps:
1. Use an NSURL Connection to grab the data from the web asynchronously
2. WHen the download is complete, convert the NSData object to a string, and manipulate the data prior to display.
3. Write the converted data out to the doc folder
4. Load the data into the UIWebView from the file
But in my current app, I have no need to manipulate the data that I load from the web. I simply want to download asynchronously, and load it into a UIWebView while that view is not yet visible. Then show that view later, when I need it.
Would it be better to use a loadRequest message that was dispatched as a block to GCD? Is that workable? I'm trying to avoid the whole mess of writing to a local file, then reloading the page from that file. Suggestions?

Why not just give the NSURLRequest directly to the webview ?
It's perfectly capable of loading data from the web itself if you don't need to massage the data in transit.

Try like this
NSURL *url = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webview loadRequest:request];
All the best.

UIWebView
You can load the request like #Warrior has mentioned
The main advantage is its loaded asynchronously and you don't have to manage everything like #Kevin Ballard has mentioned.
NSURL *url = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webview loadRequest:request];
UIWebViewDelegate
But if you want to be notified when the url is load completely.You have to conform to the UIWebViewDelegate
Header
#interface YourController : UIViewController <UIWebViewDelegate>
Implementation
1.you have to set the delegate to self
self.yourWebView.delegate = self;
2.you have to implement the following delegate that is where you will be notified when the request loading is completed.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
// Do whatever you want here
}
3.you have to set webview delegate to nil and stop loading the request and to prevent yourself from notorius EXC_BAD_ACCESS Bug due dangling pointer.You can find more about here
// If ARC is used
- (void)dealloc {
[_webView setDelegate:nil];
[_webView stopLoading];
}
// If ARC is not used
- (void)dealloc {
[webView setDelegate:nil];
[webView stopLoading];
[webView release];
[super dealloc];
}
// ARC - Before iOS6 as its deprecated from it.
- (void)viewWillUnload {
[webView setDelegate:nil];
[webView stopLoading];
}
Note:
You should not embed UIWebView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.
I hope this covers most needed basic things

Related

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;

reload a UIWebView

I'm using a UIWebView like that in the viewDidLoad:
webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 88, 320, 400)]; // init and create the UIWebView
webView.autoresizesSubviews = YES;
webView.userInteractionEnabled = NO;
webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
[webView setDelegate:self];//set the web view delegates for the web view to be itself
NSURLRequest *requestObject = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com"]];//Create a URL object & Set the URL to go to for your UIWebView
[webView loadRequest:requestObject];//load the URL into the web view.
[self.view addSubview:webView];//add the web view to the content view
[webView release], webView = nil;
When I try to change the page, I try that BUT it doesn't working :
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.facebook.com"]]];
[webView reload];
The code that's just above is in the action of a TabBar button.
**EDIT :
When I comment
[webView release], webView = nil;
I can see the apple website but not facebook when I push the button! The screen is refreshing in the apple website and not facebook...**
Hundred of thanks to help ;-)
You've released and set your webView to nil. So the object no longer exists. You are calling loadRequest and reload on a nil object which will do nothing.
Assuming you have webView as an instance variable in your class, remove the line
[webView release], webView = nil;
and instead put that in your dealloc method otherwise when you call
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.facebook.com"]]];
then you will be calling it on a nil object which will do nothing.
Where did you try this code ?
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.facebook.com"]]];
[webView reload];
You already released webview and make it Nil. So it will not work if you did it after it loads www.apple.com.
[webView release], webView = nil;
Remove above two lines once and then try. It should work.
Hope this help.
The potential problem I see is that you are setting the webView value to nil after adding it as subview, but before doing the reload:
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.facebook.com"]]];
[webView reload];
here webView is nil... the object still exists (because it is embedded in a view), but the variable does not point to it anymore, so messages are simply ignored.
no need of reload
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.facebook.com"]]];
}
this may help..!!
Reading your code, I guess that the your webView is declared as #property in the header file. You release this object after the Apple site is loaded. I think that's the reason why it doesn't load the facebook website.
The [webView release]; should be placed within the - (void) dealloc method only.
Please let me know if it works!

Return to app behavior after phone call different in native code than UIWebView

According to Apple's documentation, in order to make phone call from my app, I need to implement the following protocols:
HTML link:
1-408-555-5555
Native application URL string:
tel:1-408-555-5555
However, upon completion of a phone call initiated from an HTML link inside a UIWebView, I am redirected right back to my application. But upon completion of a phone call made from a native application URL string, my iphone stays in the iphone's regular phone application, and if I want to return to my application I have to do so manually.
As far as I can tell from reading what others have said, there is no way to change this behavior.
Here is my question:
Is it true that it's impossible
to return to an application after
making a phone call from a native
application URL string?
Would there be any downside to
implementing a UIWebView instead of
a UILabel in situations where I
really wanted the user to be
redirected back to my application
after completing a phone call?
The simplest way seems to be:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt:0123456789"]];
You will get a prompt and your app will regain focus after the call is finished.
Behavior does differ between calling -[UIApplication openURL:] with a tel: URL, and clicking a link to the same URL in a UIWebView.
Using a UIWebView instead of a UILabel might have some downsides, but you don't have to actually display the UIWebView to get its tel URL handling behavior. Instead, just load a tel URL request in an instance of UIWebView without adding it to your view hierarchy.
For example:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface PhoneCaller : NSObject
{
#private
UIWebView *webview;
}
- (void)callTelURL:(NSURL *)url;
#end
#implementation
- (id)init
{
self = [super init];
if (self)
{
webview = [[UIWebView alloc] init];
}
return self;
}
- (void)callTelURL:(NSURL *)url
{
[webview loadRequest:[NSURLRequest requestWithURL:url]];
}
- (void)dealloc
{
[webview release];
[super dealloc];
}
#end
Allow me to simplify a bit. All you need is this little snippet:
UIWebView *callWebview = [[UIWebView alloc] init];
NSURL *telURL = [NSURL URLWithString:#"tel:number-to-call"];
[callWebview loadRequest:[NSURLRequest requestWithURL:telURL]];
which I got here.
*Recently tested successfully on iOS 5.0.
The Eric's Brotto method still works in 5.1. You have to add the webview to the main view before the loadRequest, like this:
NSString *cleanedString = [[phoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:#"0123456789-+()"] invertedSet]] componentsJoinedByString:#""];
NSString *escapedPhoneNumber = [cleanedString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *telURL = [NSURL URLWithString:[NSString stringWithFormat:#"tel://%#", escapedPhoneNumber]];
UIWebView *mCallWebview = [[UIWebView alloc] init] ;
[self.view addSubview:mCallWebview];
[mCallWebview loadRequest:[NSURLRequest requestWithURL:telURL]];
(I added a phone number cleaner, to delete any non-number char that blocks this method)

Cannot load alternating urls with UIWebview

I have one view holding a list of videos(buttons which can be clicked, each hold a url) which currently bring up a new view which holds the UIWebview, the only problem is I cant pass the url to the webview depending on which button was clicked.
At the moment I just get an empty UIWebview.
How can the url string be passed to the webview so it can load the correct url for each button?
Regards
NSURL *videoURL = [NSURL URLWithString:#"http://..."];
[webView loadRequest:[NSURLRequest requestWithURL:videoURL]];
UPDATE:
In response to comment #3, here's what you can do:
This goes without saying, but keep a reference to the UIWebView instance in Browser
Add an NSString or NSURL #property to Browser
Pass the URL to the Browser instance right after init
In viewDidLoad:, call loadRequest:
So your code might look like this:
- (void)buttonClicked {
Browser *browser = [[Browser alloc] initWithNibName:nil bundle:nil];
browser.URL = [NSURL URLWithString:#"http..."];
[self presentModalViewController:browser animated:YES];
[browser release];
}
and in Browser's viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[webView loadRequest:[NSURLRequest requestWithURL:URL]];
}

webViewDidFinishLoad exception

I have a screen with a webView in my navigation controller stack and when I navigate from this view back to a previous before the page completely loaded I get a EXCEPTION_BAD_ACCESS. Seems, that the view with a webView being released before it comes to webViewDidFinishLoad function. My question is how to overcome this problem? I don't expect from the user to wait till the page loads... The code is very simple:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSURL *url = [NSURL URLWithString:storeUrl];
//URL Requst Object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView.
[browser loadRequest:requestObj];
}
TIA
I'm guessing that you have your browser.delegate property set to your custom UIViewController. When you hit the back button, this controller is popped off the navigation stack and dealloc'd, leaving your browser.delegate pointing at freed memory. When your page finishes loading, the UIWebView calls a method on its delegate, which no longer exists, so you get EXC_BAD_ACCESS.
To prevent bugs like this, any time you set an object's delegate property, make sure you set that property to nil in your dealloc, like this:
- (void)dealloc {
self.browser.delegate = nil; // Prevents EXC_BAD_ACCESS
self.browser = nil; // releases if #property (retain)
[super dealloc];
}
Since nil silently swallows any messages it receives, this will prevent your EXC_BAD_ACCESS.