How to detect when a NSURLConnection has finished - objective-c

I'm trying to use NSURLRequest and NSURLConnection to get a small bit of data (around 50 bytes) from a web API. I'm pretty sure the code below is right, but how do I actually get the received data and detect when its all downloaded?
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:req delegate:self];

By implementing NSURLConnectionDelegate, you can get the data in connection:didReceiveData: method and the connectionDidFinishLoading: method will be called when the the operation is over. Meanwhile , connection:didFailWithError: will be called if there is some error during the operation.

you set yourself as the delegate and the connection will send you calls as it goes.
example:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html

You have to use delegate's methods, read the documentation here: http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSURLConnectionDelegate

Related

ASIFormDataRequest: unable to send file to server using asynchronous request

I would like to send a file asynchronously to the server; however, it seems like when I do send the request to the server. The server gives me a HTTP code: 200, which is OK but no file is being uploaded to the server.
However, when I leave it to synchronous... it works perfectly. Weird..
Any ideas would be greatly appreciated,
- (void) sendCSVtoServer: ( Session * ) archive_session {
NSLog(#"file name: %#", [archive_session getFile]);
NSURL *url = [NSURL URLWithString:#"http://xx.x.xxx.xxx:3000/xxx/xxxxxxxx"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue: [archive_session getEmail] forKey:#"email"];
[request addFile: [archive_session getFile] forKey:#"csv"];
[request setDelegate:self];
[request startSynchronous];
}
Thanks!
You are setting a delegate, but you mention you did not implement any of those methods. ASIFormDataRequest extends ASIHTTPResquest, and therefore inherits all its properties.
You will have to implement methods decalred in ASIHTTPRequestDelegate, at least
- (void)requestFinished:(ASIHTTPRequest *)request;
and
- (void)requestFailed:(ASIHTTPRequest *)request;
Maybe others depending on your needs.
Your upload is probably still working (can you check your server?), but, when you send the request asynchronously, you don't have any way to determine if the request has succeeded or failed; right now you are just sedning and forgetting.
All the methods declared in ASIHTTPRequestDelegate.h are marked as optional, which is why the debugger, compiler, and runtime is not complaining.

Connecting with NSURLRequest

I'm using this code:
NSString *recievedData;
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.site.com/"]
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.
recievedData = [NSMutableData data];
NSLog(#"%#", recievedData);
} else {
// Inform the user that the connection failed.
NSLog(#"Unsuccessful.");
}
It's a modified version of this.
My problem is that it always returns
<>
Whether I'm connected to the internet or not, it always goes to successful.
You haven't received any data, you have just instantiated the object that will hold the received data. You need to implement the delegate methods for handling responses and failures and it is usually best to use NSURLConnection asynchronously.
There is some example code Using NSURLConnection
NSURLConnection doesn't work that way. You start a connection and then receive callbacks as data is received.
If you want a simple call to retrieve remote data, use NSData's dataWithContentsOfURL method. However, you should only use that on secondary threads because otherwise it will lock up your user interface for the duration of the call and the system may terminate your app if it takes too long.
See the full code at NSURLConnection example.

Asynchronous NSURLConnection call

I am making a Asynchronous NSURLConnection call and downloading the data, how can I know when this thread is completed?
I am making this call from viewDidLoad, and obviously NSURLConnection is intuitively running in separate thread. So how would I know if the thread is completed and second wait until the thread gets completed to get the data pulled to the viewcontroller.
You will need to assign a delegate to the NSURLConnection that handles the processing and what-not of the data. Check out the documentation, it's pretty straightforward!
code speaks for itself
-(void) startRequest {
NSURLRequest* req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://stackoverflow.com"]];
[[NSURLConnection alloc] initWithRequest:req delegate:self];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
}

NSURLConnection synchronous problem

I am writing an iPhone app which will call a webservice method by using soap message format.
I need a synchronous process because table view needs those data before it can be displayed.
So I use [NSURLConnection sendSynchronousRequest:returningResponse:error:]
The problem is, the whole program will exit without any error message after the method call.
Even I put a NSLog statement just after the
[NSURLConnection sendSynchronousRequest:returningResponse:error:],
there is no any output so I am sure the program exit during that method call. Actually during
that HTTP request and response stuff.
However, if I set a breakpoint before that method call, and run the program in debug mode,
everything runs well, the program will not exit, and I got my results as well.
Can anyone figure out what is going on?
Thanks.
- (void) sendSyncHTTPRequest:(NSString *)request_data operation:(ServOperationSync *)serv_ops {
id<ServiceData> serv_data = serv_ops.dataDelegate;
NSURL *urlAddr = [NSURL URLWithString:[serv_data getServURL]];
urlRequest = [NSMutableURLRequest requestWithURL:urlAddr
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:90];
NSData *requestData = [request_data dataUsingEncoding:NSUTF8StringEncoding];
[urlRequest setValue:#"MobilePortal" forHTTPHeaderField:#"User-Agent"];
[urlRequest setValue:[serv_data getSoapAction] forHTTPHeaderField:#"SOAPAction"];
[urlRequest setValue:[NSString stringWithFormat:#"%u", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[urlRequest setValue:urlAddr.host forHTTPHeaderField:#"Host"];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:requestData];
NSLog(#"just before sending http request");
[serv_ops.responseData setData:[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&urlResponse error:&urlError]];
NSLog(#"after sending http request");
}
Note that urlResponse and urlError are declared as instance variables.
You didn't provide us enough code to find out why your app doesn't behave correctly.
Using [NSURLConnection sendSynchronousRequest:returningResponse:error:] is generally a bad idea, because it blocks the current thread. You are probably calling it from the main thread, this will block the UI. The app won't respond to touches and feels like frozen, when the request takes long (especially on low bandwidth connection like EDGE).
The nature of networking is asynchronous. So I'd advise you to make an asynchronous request instead or use GCD. Update the Tableview in delegate methods (connection:didReceiveData: etc.). You may save the tableview data in an NSMutableArray and call [tableView reloadData] after modifying the array. The tableview would then be constructed from that array in the UITableViewDataSource delegate methods.
You need:
a run loop on your code
and don't forget your NSURLConnection
delegates

Why release the NSURLConnection instance in this statement?

I read this in a book.
-(IBAction) updateTweets
{
tweetsView.text = #"";
[tweetsData release];
tweetsData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:#"http://twitter.com/statuses/public_timeline.xml" ];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
[activityIndicator startAnimating];
}
In this statement,is that correct to release the "connection" instance at that time? After releasing it which means this NSURLConnection instance will be destroyed since it's reference count is 0 ,how are we going to make this connection operation work after release this instance? THANKS.
I thought we should release it in one of the following callback methods,right?
connectionDidFinishLoading:
connection:didFailWithError:
It's actually fine to release it there, once the connection is sent out via initWithRequest, the only thing that matters is that the delegate exists or I believe the response will just be silently lost.
From what I can tell, the only reason to not release it there is if you want to call [connection cancel] at some point in one of the delegate functions, in which case it would be best to do what you suggest and release it in BOTH connectionDidFinishLoading and didFailWithError since only one of them will be called (right?).
Edit: For a more thorough answer, NSURLConnection initWithRequest is an asynchronous request. So it actually spawns it's own thread (but calls the delegate functions on the thread that called initWithRequest). So basically, on the thread that calls initWithRequest you are actually done with the connection object and you can release it. All the while it's doing stuff on some other thread that you don't need to be concerned with.
Also I should note that if you do release it there, make sure you DON'T release it in the finish/fail methods, because it won't be a valid object.