I want to read the data in the UIWebView response when it succeeded loading the url.
Catching this data in this method didn't give me the response:
- (void) webViewDidFinishLoad:(UIWebView *)_webView {
EDIT:
I want to catch the NSURLResponse
Thanks,
Nur
Have you implemented –webView:didFailLoadWithError: ?
Probably an error when loading the URL.
I don't know enough about the architecture of your app to really say, but it might be useful for you to know that you can call arbitrary JavaScript on the page in your UIWebView from outside the UIWebView, and get the response back:
NSString *script = #"$('#textInputField').value";
NSString *result = [webView stringByEvaluatingJavaScriptFromString:script];
If you store the response in a JavaScript variable, you should be able to read it back up into your Obj-C this way.
Related
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.
I am handling a UIWebView so that i can control which URLs should be loaded within or not, but some how even though it is retuning the NO , it still load the page. Although documentation clearly says that if you return NO, the UIWebView wont load the page.
When i debug,i can see it is returning NO but still UIWebView does load the URL.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"%#", [[request URL] absoluteString]);
NSString *fullURL = [[request URL] absoluteString];
NSRange range = [fullURL rangeOfString:#"#"];
if (range.length != 0) {
NSLog(#"We need to show the other view");
return NO;
}
return YES;
}
I solved the issue, documenting here so it may help someone else. Actually, the HTML, which we were loading using some javascript which was causing this issue. I found out by just using few plain html and testing with them. Once , we know the HTML is issue, we fixed the html and its working now.
Set a breakpoint or NSLog right before the return YES part. Maybe your method gets called twice for whatever reason, and it returns NO on one, and YES on the other.
First, make sure that you are setting the delegate in viewDidLoad with
webView.delegate = self;
(take care of not setting it 2 times, in a xib file and in viewDidLoad, it has caused me problems before)
Make sure you implement the UIWebViewDelegate in your class, something like this:
#interface RootViewController : UIViewController<UIwebViewDelegate>
Assuming you have taken care of all this and still you face problems. Also since you debugged and are SURE that the delegate method is returning NO. One reason I can think of as to why this is happening is that you are not loading a new page but using something like AJAX.
I tested the following code on 2 kinds of pages:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(#"THE loadCount is %d", self.loadCount);
if (self.loadCount > 1){
return NO;
}
self.loadCount++;
return YES;
}
Case 1: A webpage where every URL loads a new page. The above code works in this case, and I cannot load any pages after the first load, as required.
Case 2: A webpage in which the first load is a complete new web page. But everything else is loaded with AJAX, in that case, my loadCount does not increase and the pages load fine.
That's all I can think of with the data provided. :)
Same issue here, just to extend the answer above be careful when using rails 4 as backend because turbolinks add javascript to every link and then you can get wrong behavior on your delegate, happened to me returning NO on shouldStartLoadWithRequest and still see the request on my server.
I am working on a browser that has back and forward buttons, that when tapped, should immediately display the URL of the page being loaded. Currently I do something like [webView goBack]; and then implement the delegate UIWebView method:
- (void)webViewDidStartLoad:(UIWebView *)aWebView {
NSLog(#"began loading URL: %#", aWebView.request.URL);
}
But this doesn't result in the behavior I expect.
For example, if I start out at www.google.com and then navigate to www.aol.com and then press the back button causing the web view's goBack code to be called, the NSLog will output began loading URL: http://www.aol.com/ even though it should state that google.com is being loaded. The google page will load perfectly however in the web view. What I don't understand is why the URL isn't consistent with what is being loaded. On occasion the log will spit out that aol.com is being loaded, followed by google.com, but this only happens sometimes. Is this a bug with the SDK or am I missing something?
Thanks in advance.
try in this delegate method
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(#"Request Url:%d",request.URL.absoluteURL);
}
I suggest to use an array of string every time you load a new url you add it in the array and beside it define a global counter increase/deacrease based on back/forward click so you can get the url easy like this
NSString *urlString = [urlArray objectAtIndex:theCounterValue];
try:
NSString *currentURL;
currentURL = [[NSString alloc] initWithFormat:#"%#", webView.request.mainDocumentURL];
I am using stringWithcontentsofurl to download some strings from my web server to the App, but i would like to update the UI to show A loader of some kind. I am downloading a number of strings (it can be sometimes as much as 100) so it would be neat for the user to show something so they know the App isn't crashing, because now the UI is stuck, i can't show A UILoader or something like that. Is there an option to do so? Or maybe A alternative to stringWithcontentsofurl where this is possible?
greets,
Erik
Try this. It loads stuff in background. If updating the UI later (in asyncload), be sure to do that on main thread.
-(void)loadappdetails:(NSString*)appid {
NSString* searchurl = [#"https://itunes.apple.com/lookup?id=" stringByAppendingString:appid];
[self performSelectorInBackground:#selector(asyncload:) withObject:searchurl];
}
-(void)asyncload:(NSString*)searchurl {
NSURL* url = [NSURL URLWithString:searchurl];
NSError* error = nil;
NSString* str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (error != nil) {
NSLog(#"Error: %#", error);
}
NSLog(#"str: %#", str);
}
This is a classic case for "Lazy Loading". See Apple's example code:
http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
It should be easy to substitute "strings" for "images" as you read that code.
You want to display a placeholder in the label like "(fetching information)" or similar and then load the information in the background, either threading the fetches yourself (asynchronous fetching) or using a library like ASIHTTPRequest that handles all the asynchronous nuts and bolts for you, calling a delegate method once the fetch has completed.
Unfortunately, stringWithContentsOfURL is a synchronous method, meaning it will block your thread and you will not receive any callbacks while it is running. This is also bad for user experience.
The alternative would be to use NSURLConnection to manually setup your own request, and tap into the delegate methods of your connection to display some sort of progress bar. Specifically, you'll want to use connection:didReceiveData: and connectionDidFinishLoading:
Once all the data has been received, use the following to get your string.
NSString *theString = [[NSString alloc] initWithData:yourData encoding:UTF8StringEncoding];
To make this method asynch it is possible and recommendable to use Grand Central Dispatch. If anyone is interested I will show the few lines of code to do that.
How can I use the UIWebView in Xcode so that when it loads up pages it DOESN'T download the images (to cause a faster loading page)?
UIWebView is a pale, poor little shadow of WebKit's full WebView, for which this is easy. -webView:shouldStartLoadWithRequest:navigationType: only gets called for navigation. It doesn't get called for every request like WebPolicyDelegate does on mac. With UIWebView, here's how I would attack this problem:
Implement -webView:shouldStartLoadWithRequest:navigationType: and set it to always return NO. But you'll also take the request and spawn an NSURLConnection. When the NSURLConnection finishes fetching the data, you're going to look through it for any IMG tags and modify them to whatever placeholder you want. Then you will load the resulting string into the UIWebView using -loadHTMLString:baseURL:.
Of course parsing the HTML is not a trivial task on iPhone, and Javascript loaders are going to give you trouble, so this isn't a perfect answer, but it's the best I know of.
expanding on Rob's answer.
I noticed that when loadHTMLString:baseURL: and always returning NO, that webView:shouldStartLoadWithRequest:navigationType: just keeps getting called. (i suspect loadHTMLString invokes another shouldStartLoadWithRequest).
so what I had to do was alternate between returning YES/NO
and I used NSScanner to parse the HTML and change src="http://..." to src=""
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if (pageHasNoImages==YES)
{
pageHasNoImages=FALSE;
return YES;
}
NSString* newHtml;
NSString* oldHtml;
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
oldHtml=[[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
newHtml=[self.detail scannerReplaceImg:oldHtml]; // my own function to parse HTML
newHtml=[self.detail scannerReplaceAds:newHtml]; // my own function to parse HTML
if (newHtml==nil)
{
NSLog(#"newHtml is nil");
newHtml=oldHtml;
}
[oldHtml release];
pageHasNoImages=TRUE;
[web loadHTMLString:newHtml baseURL:request.URL];
return NO;
}
Be the delegate for the UIWebView, then intercept the call:
– webView:shouldStartLoadWithRequest:navigationType:
Check the values of navigationType in the documentation. I believe you'll be best served by returning NO on navigationType == UIWebViewNavigationTypeOther.
does this actually cause the page to load faster?
it sounds like the images are still being downloaded, but we're just not feeding them to the UIWebView.
or does shouldStartLoadWithRequest just load the HTML text first?