Why doesn't this code work? It shows the Google screen but it doesn't change the text box value. I confirmed that the JS does work by running it in Safari, and this code seems to work otherwise since running alert('hi') does work.
NSURL *web_url = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *web_request = [NSURLRequest requestWithURL:web_url];
[web_screen loadRequest:web_request];
NSString *js_result = [web_screen stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('input')[1].value='test';"];
Just expanding on the previous answer. You need to conform to the UIWebViewDelegate protocol by setting the delegate property of the UIWebView like this:
web_screen.delegate = self;
Then you can implement one of the delegate methods to know when a request has finished loading and is therefore ready to have scripts run like so:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *js_result = [webView stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('input')[1].value='test';"];
}
For more information on the UIWebViewDelegate protocol visit the Apple site http://developer.apple.com/library/ios/#documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html
The Load URL action takes place asynchronously. It does not even start until your method has ended. So your javascript is being pushed into an empty UIWebView, then your method ends, then the load happens.
You need to let your method end before the js is pushed in. The standard approach for this is to use a Delegate object, which will have a method called on it when the load completes. Only then does it make sense to push in the javascript.
Does it work if you wait for the page to finish loading first?
Consider looking at NSURLConnection and its delegate methods. You can use these to check on the status of a download.
#interface
...
NSURLConnection *connectionInProgress;
NSData *googleRequestResponseData;
NSURL *googleURL;
...
#implementation
...
- (void) setUpRequest {
googleURL = [[NSURL URLWithString:#"http://www.google.com/"] retain];
googleRequestResponseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];
connectionInProgress = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
#pragma mark NSURLConnection delegate methods
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[googleRequestResponseData appendData:data];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[web_screen loadData:googleRequestResponseData MIMEType:#"application/octet-stream" textEncodingName:#"utf-8" baseURL:googleURL];
NSString *js_result = [web_screen stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('input')[1].value='test';"];
NSLog (js_result);
[googleURL release];
[googleRequestResponseData release];
[connectionInProgress release];
connectionInProgress = nil;
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog (#"Connection failed to load data from Google!");
[googleURL release];
[googleRequestResponseData release];
[connectionInProgress release];
connectionInProgress = nil;
}
Alternatively, check out Ben Copsey's ASIHTTPRequest wrapper, which includes a simplified approach to asynchronous downloads (see ASINetworkQueue, specifically).
You can use ASINetworkQueue to run a method of your choice (to run the Javascript code, for example), once the request download is complete.
add '.innerHTML' after what you are searching for
In your case do the following
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *js_result = [webView stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('input')[1].value='test'.innerHTML"];
}
This worked for me .
check this for more info here
Related
A weird problem.
I wanna load an image from web, so i use NSURLConnection to do it.
Everything is ok when i do testing my code on ios4.3.
But when i'm launch my app on ios5.0, i found the connection:didreceiveData haven't been called whatever what i did.
otherelse functions is called normally, just like connectionDidFinishLoading in ios4.3 and connectionDidFinishDownloading in ios5.0.
so u guys, who can help me, thanks advanced!
-(void)load
{
if(isDownloading){
return;
}
if(conn != nil){
[conn release];
}
if(data != nil){
[data release];
data = nil;
}
[self isDownloading:YES];
ImageDownloadData* imageDownloadData = [imageList objectAtIndex:count];
NSURL* url = [imageDownloadData url];
NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(conn){
[conn start];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)rd
{
NSLog(#"data");
if(!data){
data = [[NSMutableData alloc] initWithData:rd];
return;
}
[data appendData:rd];
}
I can't be sure if this is the same problem you're having, but I had a similar issue, and resolved it by taking out the in methods and references to NSURLConnectionDownloadDelegate. Apparently delegates of NSURLConnection can only implement one of the two protocols that are derived from NSURLConnectionDelegate at a time.
There's been some odd API changes between 4.3 and 5.0. Apple changed the NSURLConnectionDelegate from an informal protocol to a formal one, and branched out some of the methods into two additional subprotocols: NSURLConnectionDataDelegate and NSURLConnectionDownloadDelegate. (Oddly though, they depreciated the identical methods in NSURLConnectionDelegate but didn't document where they moved to.)
I've been noticing when compiling my code against the 6.0 API that I've been having trouble getting Cocoa Touch to call connection: didReceiveData: if I Implement methods from both NSURLConnectionDataDelegate and NSURLConnectionDownloadDelegate. All the other methods I implemented were called as expected.
In My project I am using image view which downloads image from server. It is working fine on iOS 4 but it is not showing on iOS 5.
Is there any minimum resolution needs to be take care while using iOS 5. One of image which comes from server is of 72 dpi resolution which works on iOS 4 but not on iOS 5.
I have written category to image view which will download code from image URL
Here is code snippet:
- (void) setImageFromServer:(NSString *) imageURL
{
if (imageURL!=nil)
{
ImageDownloader *imageDownloader = [[[ImageDownloader alloc] init] autorelease];
imageDownloader.requester = self;
[imageDownloader startDownload:imageURL];
}
}
- (void) didDownloadImageData:(NSData *) data forImageURL:(NSString *) imageURL
{
[self setImage:[UIImage imageWithData:data]];
}
In downloader file :
- (void) startDownload:(NSString *)MyimageURL {
self.imageData = [NSMutableData data];
self.currentImageURL = MyimageURL;
self.downloadConnection = [NSURLConnection connectionWithRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:self.currentImageURL]]
delegate: self];
[self.downloadConnection start];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[imageData appendData:data];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[self.requester didDownloadImageData:self.imageData forImageURL:self.currentImageURL];
isRewardTagImageAvailable = YES;
[connection release];
connection = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
}
I am not sure if this is a problem, but usually when I am writing a NSURLRequest I first initialize things as follows and the insert the request into a NSURLConnection. Sort of like this. Also note that once you initWithRequst in a NSURLConnection, you do not have to tell that connection to start, it will automatically.
NSURLRequest *tempReq = [[NSURLRequest alloc] initWithURL:someURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
NSURLConnection *tempCon = [[NSURLConnection alloc] initWithRequest:tempReq delegate:self];
I mean it should not matter, but give that a shot because looking at your, code it looks fine.
I would recommend adding the didFailWithError method:
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
To your files as well because maybe your connection is failing for some reason as well.
Is your connection synchronous or async ?
If async, you shouldn't autorelease your ImageDownloader, because there are some chance that it would be released for the connectionDidFinishLoading message.
Try to alloc your ImageDownloader normally, then release it when it finishes the download (both in connectionDidFinishLoading and didFailWithError)
I have searched and tried a lot but in my application (which is using iOS 5 sdk) the NSURLConnection delegate methods gets called only when I initialise and start the connection in viewDidLoad method or on click event of any button.
But I want to call it after parsing my JSON file. And create a new connection for every record in JSON.
Can anyone tell me what is happening? Is something changed in ios sdk 5.
Here is my code:
-(void)getData:(NSString*)URL{
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:URL]];
shortURL = [NSString stringWithString:URL];
connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
//NSAssert(connection!=nil, #"no connection", nil);
[connection start];
}
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
// application specific stuff
}
The getData function is written in a class inherited from NSObject. And it is called from
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method of UITableView.
Please help me with this.
Assuming that the JSON parsing code is happening in a background thread, you have to create an NSRunLoop for that thread.
The NSURLConnection class is simply adding itself to the runloop, if none exists, no processing or delegate methods will get invoked.
connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[[NSRunLoop currentRunLoop] run];
Note: The run method will block
i have recently implemented authentication challenge log in through the iPhones UIWebView. i've got it working to the point where i get challenged then i present an alert with text fields, then send the data to the site that needs authentication.
i have not yet tried to use this on anything else besides my netgear router. But my problem is when i navigate through the settings for the router, the authentication challenge gets called, thus presenting the alert even though the user is logged in.
below is the code i'm using, any advice would be grately appreciated
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"Did start loading: %# auth:%d", [[request URL] absoluteString], _authed);
myRequest=[request copy];
if (_authed) {
NSLog(#"_authed");
_authed = NO;
// pretty sure i'm leaking here, leave me alone... i just happen to leak sometimes
[[NSURLConnection alloc] initWithRequest:request delegate:self];
return YES;
}
[[NSURLConnection alloc] initWithRequest:request delegate:self];
return YES;}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
NSLog(#"protection space %#", protectionSpace.authenticationMethod);
//if(![protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault]){
return NO;
//}
//else{
// return YES;
//}
//[protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic];}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;{NSLog(#"received response via nsurlconnection %#", connection);
NSLog(#"got auth challange %#", challenge);
UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = NO;
/*NSString *aarrgghh=[NSString stringWithFormat:#"%#",connection];
NSString *searchForMe = #"login";
NSLog (#"arrgghhh %#",aarrgghh);
NSRange range = [aarrgghh rangeOfString:searchForMe];*/
if ([challenge previousFailureCount] <=1) {
//present alert with text fields for credentials
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}}
-(void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
NSLog(#"Challenge cancelled");}
//`-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(#"received data");
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;{
NSLog(#"received response via nsurlconnection %#", response);
// THIS IS WHERE YOU SET MAKE THE NEW REQUEST TO UIWebView, which will use the new saved auth info
if(_authed){
//NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:self.webView.request.URL.absoluteString]];
[webView loadRequest:myRequest];
}
}
`
Might be a simpler way to do this, but this is what worked for me.
First off, when shouldStartLoadWithRequest returns YES, that tells UIWebView to create NSURLConnections and run them for you . Since you can't assign a delegate to this connection, that's not going to work. If you want to handle authentication via a NSURLConnectionDelegate, then shouldStartLoadWithRequest should always return NO for that UIWebView.
So you need to handle the connection yourself. Fire off an NSURLConnection with the request and use the rest of the NSURLConnection delegate methods to handle the loading (e.g. keep track of the MIME type and build up an NSMutableData)
Finally, when you get to connectionDidFinishLoading, you can call UIWebView's loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL with the NSData your connection downloaded.
I am developing an app in which I have a table. In the table cell I have an imageview ( the images are displayed via url ) and a textview/webview. I start threads for each row to get the images in the
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method ( if image is not already got ) and set the text of textview/webview from an array.
The problem arises when the images are being received and I pop the view, the application crashes giving the following message:
bool _WebTryThreadLock(bool), 0x1a0670: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Now the situation becomes more weird if I don't release the textview/webview that I added to the cell, then every thing works fine.
Edit: the crash does not happens when I replace textview/webview with a label
Hoping I am clear in my question. If any thing is confusing please comment. I need to resolve this.
Thanks,
Nikhil
That's a huge mistake to use threads. Try to avoid using threads if you have other solutions !
In your case, just use an asynchronous NSURLConnection which will take care of downloading your image while not slowing your app ;)
Here is part of the code :
- (void) startDownload {
self.activeDownload = [NSMutableData data];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:#"blablabla"]] delegate:self];
self.imageConnection = conn;
[conn release];
}
#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR DOWNLOADING");
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"FINISH DOWNLOAD");
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
self.activeDownload = nil;
self.imageConnection = nil;
//do whatever you want with your image
[image release];
}