I'm looking to create a simple iOS app that displays the current water level of a local lake. The water level is updated daily on a specific URL. Is it possible to pull content from a webpage using objective c?
Sure. Check out the URL Loading System Programming Guide. From that link:
The URL loading system provides support for accessing resources using the following protocols:
File Transfer Protocol (ftp://)
Hypertext Transfer Protocol (http://)
Secure 128-bit Hypertext Transfer Protocol (https://)
Local file URLs (file:///)
Absolutely! Use the NSURLConnection object. Use something like the function below, just pass an empty string for 'data' and then parse the HTML returned to find the value you're looking for.
-(void)sendData:(NSString*)data toServer:(NSString*)url{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSData *postData = [data dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d",[postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Current-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if(conn){
//Connection successful
}
else{
//Connection Failed
}
[conn release];
}
Easier way yet using threading:
- (void)viewDidLoad
{
[self contentsOfWebPage:[NSURL URLWithString:#"http://google.com"] callback:^(NSString *contents) {
NSLog(#"Contents of webpage => %#", contents);
}];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void) contentsOfWebPage:(NSURL *) _url callback:(void (^) (NSString *contents)) _callback {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:_url];
dispatch_sync(dispatch_get_main_queue(), ^{
_callback([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
});
});
}
Related
I want to send one data with POST method to one url and received answer from that url.
I write this code for send data ("a") to this url ("http://www.test.com/test/msht")
this is my code but not working please guide me how to send data and give answer from url.
-(IBAction)btn_post_clicked:(id)sender{
//if there is a connection going on just cancel it.
[self.connection cancel];
//initialize new mutable data
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData = data;
[data release];
//initialize url that is going to be fetched.
NSURL *url = [NSURL URLWithString:#"http://www.test.com/test/msht"];
//initialize a request from url
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[url standardizedURL]];
//set http method
[request setHTTPMethod:#"POST"];
//initialize a post data
NSString *postData = [[NSString alloc] initWithString:#"a"];
//set request content type we MUST set this value.
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
//set post data of request
[request setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]];
//initialize a connection from request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.connection = connection;
[connection release];
//start the connection
[connection start];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.receivedData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"%#" , error);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//initialize convert the received data to string with UTF8 encoding
NSString *htmlSTR = [[NSString alloc] initWithData:self.receivedData
encoding:NSUTF8StringEncoding];
NSLog(#"%#" , htmlSTR);
}
My friend your code is wrong!!! you should determine name of post value in post NSString....
you don't send a value only.
you should write this code if get post method name in server is user :
NSString *post = [NSString stringWithFormat:#"user=a"];
I am trying to parse an HTML page, but the page requires a username/password to access the data.
How do I pass the credentials to the server so I can load the webpage into my NSData object?
UPDATE for Comments Below
Normally if you are using a web browser, it will pop up a login window for you to type in the credentials. When I execute it in iOS, it doesn't give me anything.
Thanks a lot!
Alan
You can use ASIFormDataRequest. Take a look at it here
NSURL *tempUrl = [NSURL URLWithString:#"http://www.yoursitetoparse.com"];
ASIFormDataRequest *request = [[ASIFormDataRequest alloc] init];
request = [ASIFormDataRequest requestWithURL:tempUrl];
[request setDelegate:self];
[request setRequestMethod:#"POST"];
[request setUsername:#"username"]; //Username
[request setPassword:#"password"]; //Password
[request startAsynchronous];
And it's delegate methods:
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Failed %# with code %d and with userInfo %#",[error domain],[error code],[error userInfo]);
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"Finished : %#",[theRequest responseString]);
}
I have a bunch of URL requests that are sent out in batch and then a 'catcher' class that recieves the results. I'm doing this through facebook's graph API SDK so I don't have control of the actual NSURL. My problem is that I don't trigger the next result protocol until all requests have come back, but sometimes, especially over 3G, they don't always come back (especially when you have a few hundred). What's a good way to 'give up' on a given request? The way the actual request works, for those who aren't familiar with the FB api, is you initialize a facebook object and then request data from it, and you specify a return delegate. So, for each individual request I have a returnDelegate (the catcher), which I can initialize specific to each request.
UPDATE: Some code from FB-API
- (FBRequest*)requestWithMethodName:(NSString *)methodName
andParams:(NSMutableDictionary *)params
andHttpMethod:(NSString *)httpMethod
andDelegate:(id <FBRequestDelegate>)delegate {
NSString * fullURL = [kRestserverBaseURL stringByAppendingString:methodName];
return [self openUrl:fullURL
params:params
httpMethod:httpMethod
delegate:delegate];
}
- (FBRequest*)openUrl:(NSString *)url
params:(NSMutableDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<FBRequestDelegate>)delegate {
[params setValue:#"json" forKey:#"format"];
[params setValue:kSDK forKey:#"sdk"];
[params setValue:kSDKVersion forKey:#"sdk_version"];
if ([self isSessionValid]) {
[params setValue:self.accessToken forKey:#"access_token"];
}
[self extendAccessTokenIfNeeded];
FBRequest* _request = [FBRequest getRequestWithParams:params
httpMethod:httpMethod
delegate:delegate
requestURL:url];
[_requests addObject:_request];
[_request addObserver:self forKeyPath:requestFinishedKeyPath options:0 context:finishedContext];
[_request connect];
return _request;
}
- (void)connect {
if ([_delegate respondsToSelector:#selector(requestLoading:)]) {
[_delegate requestLoading:self];
}
NSString* url = [[self class] serializeURL:_url params:_params httpMethod:_httpMethod];
NSMutableURLRequest* request =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:kTimeoutInterval];
[request setValue:kUserAgent forHTTPHeaderField:#"User-Agent"];
[request setHTTPMethod:self.httpMethod];
if ([self.httpMethod isEqualToString: #"POST"]) {
NSString* contentType = [NSString
stringWithFormat:#"multipart/form-data; boundary=%#", kStringBoundary];
[request setValue:contentType forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[self generatePostBody]];
}
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.state = kFBRequestStateLoading;
self.sessionDidExpire = NO;
}
As discussed above, you can implement your own timeout by instantiating an NSTimer which will signal a delegate object when a certain amount of time elapses.
I have a little Mac application which should be able to post Data to my web server which saves the data in a database. Now that's the Code I have now:
NSData *postData = [urlString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://..."]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) NSLog(#"Done");
And it works fine. But now I want to check whether the data was correct (and stored in the database) or something (like eMail) is wrong. The PHP file prints e.g. "email incorrect" out if the E-Mail is not correct.
But how can I fetch this data (which PHP prints out) in Xcode that the App knows whether it was successful or not?
Thanks for answers!
You need to implement the NSURLConnectionDelegate methods connection:didReceiveData: and connectionDidFinishLoading:
According to the docs didReceiveData: may be called multiple times per NSURLRequest (i.e. the response will not always arrive all at once) so the recommended method is to append the incoming data to buffer during connection:didReceiveData: and then do any processing on the data in connectionDidFinishLoading:.
You could create a property on your class like this:
#property (nonatomic, strong) NSMutableData *dataBuffer;
And instantiate your buffer during viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.dataBuffer = [[NSMutableData alloc] init];
// do any other setup your class requires...
}
And then implement the delegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// clear the buffer in case it has been used previously
[self.dataBuffer setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.dataBuffer appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString *response = [NSString stringWithUTF8String:[self.dataBuffer bytes]]);
NSLog(#"response from HTTP request=>%#", response);
}
This can all also be done using a third-party networking library like ASIHTTPRequest (which is no longer under active develoment) or AFNetworking, but sometimes those can be overkill depending upon what you are trying to accomplish
Implement the delegate method for the NSURLConnection,
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response.
This method is called by the app when the request finishes. You can access response data using the 'response' parameter.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
Then just convert the 'data' parameter into a string using:
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Then you can search the response for whatever string you want, e.g., "email incorrect".
PS: I generally don't use NSURLConnection/NSURLRequest for HTTP requests, I'd recommend you check out ASIHTTPRequest for really simple HTTP requests/connections.
Hope this helps.
I'm a novice in iOS developing, and have some problems with understanding web service organization. I want to send a Get query to the URL. And I do it so:
-(BOOL) sendLoginRequest{
NSString *getAction = [NSString stringWithFormat:#"action=%#&username=%password=%#",#"login",self.log.text, self.pass.text];
NSString *getUserName = [NSString stringWithFormat:#"username=%#",self.log.text];
NSString *getPassword = [NSString stringWithFormat:#"username=%#",self.pass.text];
NSData *getDataAction = [getAction dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *getLengthAction = [NSString stringWithFormat:#"%d", [getDataAction length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"http:http://www.site.fi/api/"]];
[request setHTTPMethod:#"GET"];
[request setValue:getLengthAction forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:getLengthAction];
self.urlConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
NSAssert(self.urlConnection != nil, #"Failure to create URL connection.");
// show in the status bar that network activity is starting
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
the answer may be "true" or "false"
but how can I take this answer?
You should define next methods to get answer:
Start connection: [self.urlConnection start];
Check server response:
- (void)connection:(NSURLConnection *)theConnection didReceiveResponse:(NSURLResponse *)response
Collect data that servers sends you:
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data
Be sure to manage errors:
- (void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error
Check received data:
- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection
To be more sure that you correctly understood me check NSURLConnection Class Reference
Send [self.urlConnection start]; and implement the NSURLConnectionDelegate methods to receive the response. Alternatively use ASIHTTPRequest and the block handlers, which to my way of thinking are much easier to write for beginners, provided you don't need to run on iOS pre-4.1.
You will gather the data returned as NSData; just convert that to a string, and either call boolValue on the string (check the docs for its rather strange tests), or use a specific set of your own tests.