Not able to download a file with NSURLRequest - ios

I am just new in IOS development. I've been trying to figure apple documentations. So I read this page:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html#//apple_ref/doc/uid/20001836-BAJEAIEE
and this is what I have done:
NSMutableData *testFileType;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
testFileType = [[NSMutableData data] retain];
NSLog(#"the connection is successful");
} else {
// Inform the user that the connection failed.
NSLog(#"the connection is unsuccessful");
}
[testFileType setLength:0];
[testFileType appendData:[NSMutableData data]];
Can anyone tell me what am I missing here?

Just creating the NSURLConnection is not enough. You also need to implement the didReceiveResponse and didFinishLoading delegate methods. Without these the connection downloads the file, but you never get to see it.
NSURLConnection sends a didReceiveResponse for every redirection when the headers are received. Then it sends a didReceiveData with some bytes of the file. Those you need to append to your mutable data. Finally you get a didFinishLoading where you know that you have gotten all data. In case of error you get a didFailWithError instead.
Look at the NSURLConnectionDelegate protocol documentation: https://developer.apple.com/library/mac/ipad/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/Reference/Reference.html

you should implement the following delegate methods:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error: %d %#", [error code], [error localizedDescription]);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
responseData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[responseData writeToFile:savePath atomically:YES];
}
here responseData and savePath are instance variables declared with:
NSMutableData *responseData;
NSString *savePath;
and your class must conforms the NSURLConnectionDataDelegate and NSURLConnectionDelegate protocols.
For the code to work you probably want to set savePath to a working path like this
NSString *savePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"testfile.txt"];
after the download have finished, you can do anything to the file at savePath as you wish.

Related

ios save json with GET request using objective-c

I've tried most of advises from stackoverflow but none of them was good for me.
My client wants to save user data in json with GET request in format:
http://website.com/users/save.php?save={"email":"user#domen.com","name":"Will Smith"}
I'm using objective-c
Please advise
Thanks
Edit
my php file looks like this:
<?php
$save = $_GET['save'];
$fp = fopen("save_users_ww.txt", "a+");
fputs($fp,$save."\r\n");
fclose($fp);
?>
so post don't work for me. Thank you for help again
In case someone else will need a solution, this is my code:
.h file:
#interface WelcomeViewController : UIViewController <NSURLConnectionDelegate>
{
NSMutableData *_responseData;
}
.m file:
-(void)postToDataBaseWithName:(NSString*)nameToPost andEmail:(NSString*)emailToPost {
NSString *str = [NSString stringWithFormat:#"http://website.com/users/save.php?save={\"email\":\"%#\",\"name\":\"%#\"}", emailToPost, nameToPost];
str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(conn) {
}
}
also add delegate methods to see how it works:
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
NSLog(#"didReceiveResponse");
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
NSLog(#"didReceiveData");
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSLog(#"connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
NSLog(#"didFailWithError = %#", error);
}

NSData setLength EXC_BAD_ACCESS

I am developing an IOS application. setLength method crash in didReceiveResponse. What do you think is the reason for this. What should I do prevent.
- (void) callService:(NSString*)urlString
{
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL urlString]];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:[urlString dataUsingEncoding:NSUTF8StringEncoding]];
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(theConnection) {
self.webData = [[NSMutableData data] retain];
}
else {
NSLog(#"connection is NULL");
}
}
#pragma mark Web service
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.webData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.webData appendData:data];
}
Usually, a crash on NSData usages are in fact an early release problem. A NSData initialized with [NS(Mutable)Data data] is an autoreleasable object, even though you called a retain on it.
To be sure this object doesn't get released before your didReceiveResponse gets called, initialize it with [[NSMutableData alloc] init]. That should do it
It looks like you got your memory management wrong.
In this case it's probably an overreleased NSMutableData. Proper management for this object should be done by the property webData. You did not post the declaration, yet it should be along the lines:
#property (retain) NSMutableData *webData;
If you synthesized the accessors they should do the retain/release for you.
To answer why the error happens nevertheless we need more code.
Try this, it may be help you:
this may be crash due to NULL response data so check your response data and set the following condition for the future purpose:
And synthesize your NSData:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if(responseData != NULL)
{
[responseData setLength:0];
}
}

how to wait the response from a http request in ios

Anybody knows how to wait the response of a http request? In my code, I am doing a http request to an url and then what i need to do, it is to check the http response in order to decide different treatment. I have something like this:
-(void)check{
[self fetchURL:#"http://something"];
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
}
-(void)fetchURL:(NSString *)urlWeb{
NSURL *url = [NSURL URLWithString:urlWeb];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"INSIDE OF didReceiveResponse");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"INSIDE OF didFailWithError");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"INSIDE OF connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
NSLog(#"inside of didReceiveData");
response = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"response: %#", response);
}
I have been trying different options that I have seen around here, but i cant stop the execution of my code and wait for that answer...that means when I check the response of my http request, it always appears empty or with a nil reference...
any help how to figure out??
thanks
You can't evaluate the response value right after your 'fetchUrl' call, because your request is asynchronous, and your code goes on with the execution without waiting for the answer. You will receive the response value only in one of the delegate method, so there's the place where you should check the result.
If you really want to make a synchronous request you can use sendSynchronousRequest:returningResponse:error: like this
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(data){
//use data
}
else{
//check error domain and code
}
(See the Apple NSURLConnection Reference)
But keep in mind that your program will be stuck on this call till it receives a response or goes timeout.
Why don't you write this code:
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
In - (void)connectionDidFinishLoading:(NSURLConnection *)connection; method it wouldn't execute unless you have your complete proper response.
And Just for ado: Right to way to get data properly should be:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSString *string = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
if (string)
NSLog(#"string = %#", string);
}
Did you try checking the respons witin connectionDidFinishLoading: ?
That is the very delegate method which is called when the data was transferred successfully. Before that point in time, you should not expect any meaningful data.
Besides - didReceiveData should provide you with portions of data received in the meantime. Apparently you do not seem to process it nor just to store it for later evaluation (witin connectionDidFinishLoading)

polling an external server from an app when it is launched

I am new to iOS and working on an app which runs on a real device (iPad). So, when I launch my app on the iPad after the view is visible, the app should be able poll a web server or something (without any user interaction) and get some information over HTTP and based on this information, I want fill some text fields in the app view. can you let me know if it is possible to do something like this in iOS? if so how and some sample pieces of code would be much appreciated.
Thanks.
You can download information over http using NSURLConnection in the viewWillAppear or viewDidLoad. After download the data if its XML parse using NSXMLParser (or any other XML parser for iOS).
//Lets say you have download and process method
- (void)downloadAndProcess
{
//URL you want to download Info from
NSURL* url = [NSURL URLWithString:#"http://google.com"];
//Make a mutable url request
NSMutableURLRequest* req = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
NSURLConnection* conn = [NSURLConnection connectionWithRequest:req delegate:self];
if(conn)
{
//NSMutableData receivedData is an instance variable
receivedData = [[NSMutableData alloc] init];
}
}
//NSURLConnection Delegate methods here
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error downloading data :%#",[error localizedDescription]);
// release receivedData object when connection fails
[receivedData release],receivedData = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Connection did finish downloading data which you can process based on what your data is
// release receivedData object once you are done processing it.
[receivedData release],receivedData = nil;
}

Image blank when using NSURLConnection but not when using dataWithContentsOfURL

When I use NSURLConnection asynchronously to try and get a NSData with my image data in it the image comes back as blank, but when I use dataWithContentsOfURL synchronously I have no problems and I get the image data correctly. Is there any reason why my asynchronous method would be failing?
This works:
NSData *data = [NSData dataWithContentsOfURL: url];
NSLog(#"TEST %#", data);
UIImage *map = [UIImage imageWithData:data];
mapView.image = map;
This doesn't:
//
// MapHttpRequest.m
// GTWeb
//
// Created by Graphic Technologies on 6/21/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "MapHttpRequest.h"
#implementation MapHttpRequest
#synthesize receivedData;
#synthesize dataString;
#synthesize vc;
- (void)request:(NSString *)url fromView:(UIViewController *) theVC
{
vc = theVC;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSLog(#"URL: %#", url);
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
[vc mapImageConnectionFinished:receivedData];
// release the connection, and the data object
[dataString release];
[connection release];
[receivedData release];
}
#end
It looks like you started looking at the guide on http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html but didnt finish reading it :)
You need to implement the methods that will received infomation about the data being received.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
Its all described in the link i provided.
According to your code, you didn't schedule the connection to run:
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
Did you put traces in your delegate's callbacks to make sure they are being called?
Turns out it was giving me a bad request because there was a invisible carriage return or white space. Trimming it off with:
url = [url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
fixed my problems.

Resources