UIWebView loading and general performance - iphone

I am using UIWebView to display textual content in my app (I store the content in local HTML files that I pack with the app). All together, I have three web views whose content I change dynamically based on user feedback.
Although some might argue that this is not the most accepted way, I find UIWebView very convenient to display formatted text, and modify that text using HTML if necessary. While this works 99% of the time, on occasion, I experience problems that generally fall into one of these categories:
Sometimes, the web view content loads slow and is late a second or so.
The content loads but is not showing. However, as long as, I touch the view (try to scroll or something) the content pops in.
A few times I received memory warnings (usually not long after the app's initial loading) that in no way affected the performance of my app. It logged the memory warning but the app worked like nothing happened.
This is the method I use to load content to my web views:
- (void)loadSimpleDocument:(NSString*)documentName inView:(UIWebView*)webView
{
NSString *path = [[NSBundle mainBundle] pathForResource:documentName ofType:#"html"];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
}
Aside from this, the shouldStartLoadWithRequest delegate method is also implemented, always returning a YES.
My question is: Is there a way to improve the reliability/performance of my web views (in particular loading)? Is there something I have overlooked, did wrong, or do not know about?
Some additional info:
I am on iOS6 SDK, use ARC, and do everything programmatically (do not use IB or storyboard).

You have 2 options to check what's going on:
Implement webViewDidStartLoad & webViewDidFinishLoad delegate methods to check why the content isn't showing (may be the content isn't loaded yet).
read the html content to an NSString then use loadHTMLString:baseURL instead of using loadRequest and check if it loads faster.
Hope this could help.

Related

How to create a button that links to Safari?

For legal reasons, I'm obligated to show Terms of Service in my application, a PDF on an external server. What I believe would be easiest to do would be to create a UIBarButton item and then create an IBAction that launches the link in Safari.
So I create a button:
IBOutlet UIBarButtonItem *legal;
Then I make it into a nonatomic property and synthesize it in my implementation file, right? I go on to create an IBAction:
-(IBAction)legalButtonPressed:(id)sender;
I go into my implementation file, and here's where the issue comes. When it comes to defining those actions, I become confused. As I am new to iOS development, I could use some guidance. I don't know how to force the link into safari in the action. Any help would be greatly appreciated!
Thanks!
IBOutlet and IBActions are used for Interface Builder connections. If you have your UIBarButtonItem on a xib file, you can connect its action to the controller by right clicking in the files owner object. The same with the outlet.
Once you have the action in the controller connected to the button in the xib file, (I see no need to get an outlet here), you just implement the method as follows:
-(IBAction)legalButtonPressed:(id)sender {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: #"http://yourdomain.com/legal.pdf"]];
}
this will automatically open safari with the given url
Take a look at UIApplication's documentation, it has a openURL method you might find useful.
Another option is to include your legal text in a UITextView.
Example:
By clicking Join you agree to company's
Terms of Service, found here: http://www.site.com/tos.html and
Privacy Policy, found here: http://www.site.com/privacy.html
Make sure Link Detection is turned on in the UITextView and it will automatically recognize URLs. Any clicks on those URLs will automatically launch Safari.
Although you can do this approach (i.e. launch the link in Safari). I would suggest that you try to keep the user as much as possible in your app. I am guessing this LEGAL TERMS is a HTML doc?
You can do that using UIWebView. Init a webView and do this -
NSURL *url = [NSURL URLWithString:webAddress];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[webView loadRequest:req];
This will open the url in your app only! You can make the UIWebView open up as a modal window or in many other ways...

objective C Iphone open Google map application direction page url in webview memory warning

HI, WHat am trying to do is load a google direction page directly in webview by passing the lat long values for source and destination (am getting these stored_long lat values that i have previously stored. and am not using google api) everything works fine but the prob is as soon as webview loads the direction page, it starts getting memory warning and on further browsing get crash need a solution to fix these ...am setting webview delegate to nil and also releasing webview also sometimes it crashes wen back btn is pressed ....do need urgent help...guys
NSString* url = [NSString stringWithFormat:#"http://maps.google.com/maps/m?saddr=%f,%f&daddr=%f,%f&view=map&z=13",Stored_lat3,Stored_long3,Stored_lat4,Stored_long4];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
aWebView.delegate = self;
[aWebView loadRequest:request];
Have you tried profiling your application for Allocations using Instruments?
Memory warnings tend to imply your application is using too much memory. It could be that before you even open your web view you are using lots of memory. Opening the webview could be pushing your application over the edge so to speak.
Overriding didReceiveMemoryWarning in your view controllers to clean up memory is also a good tactic to prevent your application from crashing.
I hope this helps!

Why would webview's loadHTMLString not hit webViewDidStartLoad callback?

Background: I am developing a news reader type app native for the iPhone which displays many of the news articles as html in UIWebViews. My current goal is to have a css file in my project that can style html that is programmitically meshed up (article + comments, etc). I have done a bunch of little proof of concepts and I know that I can use <link id=\"stylesheet\" rel=\"stylesheet\" href=\"Test.css\" type=\"text/css\" /> as part of the input string to webview's loadHTMLString and achieve the result of styling the html in an expected manner, using the mainbundle's bundlepath as the baseUrl input to that function. Unfortunately, this does not work when I do this in my actual project. Note here that my issue can be reproduced with simple html.
Here's the part where I scratch my head: I can use #"" as the base url and display the unstyled html as expected. But, if I use the bundlepath as the baseUrl instead, the UIWebView goes blank. Investigating further, the webViewDidStartLoad callback never hits it's breakpoint (it does in the #"" case). What would cause this not to fire? Of the 4 callbacks, the only one that fires is the shouldStartLoadWithRequest, which I return NO from. The didFailLoadWithError and the webviewDidFinishLoad are the other two.
My suspicion is that something must be wrong with the mainbundle, but I have no idea what.
I do receive this message in gdb sometimes, although this could be unrelated:
void SendDelegateMessage(NSInvocation*): delegate failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
If you were not using the touch screen for this entire interval (which can prolong this wait), please file a bug.
Code Snippets:
Note: the css link actually has no affect on this issue
UIWebView* contentView = [[UIWebView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
contentView.delegate = self;
NSString *htmlString = #"<html><body>Hello World</body></html>";
NSString *path = [bundle bundlePath];
NSURL *resourceBaseURL = [NSURL fileURLWithPath:path];
[contentView loadHTMLString:htmlString baseURL:resourceBaseURL];
Values at time of loadHTMLString call:
htmlString: "<html><body>Hello World</body></html>"
resourceBaseUrl: file://localhost/Users/U0107552/Library/Application%20Support/iPhone%20Simulator/3.1.3/Applications/D0EE8DA9-B156-47B3-BC53-9A731F813FB1/Test%20App.app/
The one difference that I can see between my working POC and my app is that gdb: po htmlString returns "[the above string] Current Language: auto; currently objective-c" in the POC but just the string in my app.
Sorry for the long-windedness.

iPhone: How to Display Text from UIWebView HTML Document in a UITextView

I have an RSS feed that gets arranged in a UITableView which lets the user select a story that loads in a UIWebView. However, I'd like to stop using the UIWebView and just use a UITextView or UILabel.
This png is what I am trying to do (just display the various text aspects of a news story):
I have tried using:
NSString *myText = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.textContent"];
and assigning the string to a UILabel but it doesn't work from where I am implementing it in webViewDidFinishLoad (--is that not the proper place?). I get a blank textView and normal webView.
If I overlay a UITextView on top of a UIWebView on its own (that is, a webView that just loads one page), the code posted above works displays the text fine. The problem arises when I try to process the RSS feed .
I've been stuck wondering why this doesn't work as it should for a few days now. If you have a better, more efficient way of doing it then placing the code in webViewDidFinishLoad, please let me know! Does it go in my didSelectRowAtIndexPath?
Thank you very much in advance!
I think the you should first log the string returned by :
NSString *myText = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.textContent"];
... in the case of the RSS feed to make sure that you are getting something back. It's possible the RSS page doesn't have the same javascript components and that it returns an empty string.
Once you've confirmed that, then it becomes a simple matter of getting it to display properly in the text view.
If the NSString you want to display is not empty, try to do something like this in the webViewDidFinishLoad method:
[yourUILabel performSelectorOnMainThread:#selector(setText:) withObject:[NSString stringWithFormat:#"bla bla %#", #"more bla"] waitUntilDone:YES];
The main thread of an iphone app is responsible for drawing components, that is why your label doesn't show your text.
You could also try setting setNeedsDisplay: to true
Also, the UILabel will not preserve the HTML format. It will display it as just text.
You could try the following:
NSString *htmlContent = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innerHTML;"];
NSString *htmlContent = [webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML;"];
NSString *htmlContent = [webView stringByEvaluatingJavaScriptFromString:#"document.body.innerText;"];
You lose out on formatting information with the last line of code.

UIWebView not responsive

I'm having trouble intercepting URL clicks within a UIWebView. I've read around and found the most common problem is that links have a target="_blank" attribute to open in a new window, but mine have no such attribute. URLs are of the form "/word", where word is some arbitrary word. I'm also encoding them with %20 when necessary. My UIWebViewDelegate class doesn't even receive a shouldStartLoadWithRequest: event, just nothing happens. I've also tried inserting a button into the HTML, and these are unresponsive too.
Are there any other rules governing which URLs UIWebView will acknowledge? I've tried using an absolute URL (and even just "http://www.google.com"), and also replacing the entire string of HTML with just a valid link to google, but all to no avail. And the really odd thing is that I can find one link that will work - it can be clicked and I successfully catch the event, but there seems (I've looked pretty hard) to be nothing different between the HTML containing this link and the others.
Given that I'm new to the iPhone platform, I figure I may very well be doing something more fundamentally wrong. Flow through the app looks like this: the main view is a UITableViewController, which lets users select from a list of words. When a word is selected, a new UIViewController is created and pushed onto the screen. This is the view with a UIWebView, which displays data loaded from a SQLite database. Some relevant bits of code are below.
//move from the UITableViewController to UIViewController with UIWebView
DetailViewController *viewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
...
[self.navigationController pushViewController:viewController animated:YES];
//load HTML and display it in a UIWebView
NSString *output = [NSString stringWithFormat:#"%#%#%#",header,definition,footer];
[definitionView loadHTMLString:output baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
Any help would be greatly appreciated - been pulling my hair out for a while with this one.
You should take a look at PhoneGap: http://phonegap.com/
PhoneGap does exactly this (basically it's a big giant UIWebViewDelegate that makes it possible to write JavaScript apps for the iPhone that are able to take advantage of the camera, GPS, accelerometer etc.). Download the source, open PhoneGap.xcodeproj in the 'iphone' folder, and take a look at class PhoneGapDelegate. This is a great example usage of UIWebViewDelegate, hard to find a better example :) And it works of course.