I would like to know how I can stop/abort a NSURLConnection while it is performing it load request.
The reason I would like to know is that, I am parsing an XML using NSURLConnection and sometimes the time taken to get a response is too long.
here is my code to make things clearer...
I am parsing an XML using NSXMLParser and loading the req with my soap message before I request it using NSURLConnection
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn)
{
webData = [[NSMutableData data] retain];
}
}
The following piece of code is what is standard
-(void) connection:(NSURLConnection *) connection
didReceiveResponse:(NSURLResponse *) response
{
[webData setLength: 0];
}
-(void) connection:(NSURLConnection *) connection
didReceiveData:(NSData *) data
{
[webData appendData:data];
}
In this, sometimes the time taken for the program to get to connection didReceiveData is too long and the user would need to abort that operation.
So I would like to know if this is possible.
I know how to abort after it starts parsing by using [parser abort] but I dont know how to abort the NSURLConnection.
It would be great if someone could help me out with this.
Use [conn cancel]; to stop an ongoing download.
Related
This is first time I am trying.
Till now I am successful in getting DATA from SERVER in JSON format.
Now what I want to do is,
I have two NSString values that I have to send to server and server will check for them.
I don't know what checking mechanism is behind.
I am just sending two strings and server will return me try or false.
And I have to show that true or false thing.
All this will be called onClick of UIButton
Here what I tried,
NSString *str = [NSString stringWithFormat:#"http://XXXXXXXXXXXXXXXXXXXXXXX/api/CaptchaImage/CheckCaptchValid?validstring={%#}&encodestring={%#}",string1,string2];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
[req setURL:[NSURL URLWithString:str]];
NSURLConnection *connGet = [[NSURLConnection alloc]initWithRequest:req delegate:self];
if(connGet)
{
NSLog(#"Connected successfully");
}
else
{
NSLog(#"Not connected successfully");
}
It gives me NSLog as connected successfully,
But I am struck here,
I want a response from server too in NSString format, either True or False.
Can any one guide me for further steps.
I tried some SO links, but didn't get much.
Thanks in advance.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[myData appendData:data];
}
-(void)connectionDidFinishLoading: (NSURLConnection *)connection {
response = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
}
Try this, but I have not tested this code. add appropriate delegate method.
Hope this will work for you
I've read through tons of messages saying the same thing all over again : when you use a NSURLConnection, delegate methods are not called. I understand that Apple's doc are incomplete and reference deprecated methods, which is a shame, but I can't seem to find a solution.
Code for the request is there :
// Create request
NSURL *urlObj = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlObj cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
[request setValue:#"gzip" forHTTPHeaderField:#"Accept-Encoding"];
if (![NSURLConnection canHandleRequest:request]) {
NSLog(#"Can't handle request...");
return;
}
// Start connection
dispatch_async(dispatch_get_main_queue(), ^{
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; // Edited
});
...and code for the delegate methods is here :
- (void) connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Receiving response: %#, status %d", [(NSHTTPURLResponse*)response allHeaderFields], [(NSHTTPURLResponse*) response statusCode]);
self.data = [NSMutableData data];
}
- (void) connection:(NSURLConnection *)_connection didFailWithError:(NSError *)error {
NSLog(#"Connection failed: %#", error);
[self _finish];
}
- (void) connection:(NSURLConnection *)_connection didReceiveData:(NSData *)_data {
[data appendData:_data];
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)_connection destinationURL:(NSURL *) destinationURL {
NSLog(#"Connection done!");
[self _finish];
}
There's not a lot of error checking here, but I've made sure of a few things :
Whatever happens, didReceiveData is never called, so I don't get any data
...but the data is transfered (I checked using tcpdump)
...and the other methods are called successfully.
If I use the NSURLConnectionDownloadDelegate instead of NSURLConnectionDataDelegate, everything works but I can't get a hold on the downloaded file (this is a known bug)
The request is not deallocated before completion by bad memory management
Nothing changes if I use a standard HTML page somewhere on the internet as my URL
The request is kicked off from the main queue
I don't want to use a third-party library, as, ultimately, these requests are to be included in a library of my own, and I'd like to minimize the dependencies. If I have to, I'll use CFNetwork directly, but it will be a huge pain in the you-know-what.
If you have any idea, it would help greatly. Thanks!
I ran into the same problem. Very annoying, but it seems that if you implement this method:
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
Then connection:didReceiveData: will never be called. You have to use connectionDidFinishLoading: instead... Yes, the docs say it is deprecated, but I think thats only because this method moved from NSURLConnectionDelegate into NSURLConnectionDataDelegate.
I like to use the sendAsynchronousRequest method.. there's less information during the connection, but the code is a lot cleaner.
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (data){
//do something with data
}
else if (error)
NSLog(#"%#",error);
}];
From Apple:
By default, a connection is scheduled on the current thread in the
default mode when it is created. If you create a connection with the
initWithRequest:delegate:startImmediately: method and provide NO for
the startImmediately parameter, you can schedule the connection on a
different run loop or mode before starting it with the start method.
You can schedule a connection on multiple run loops and modes, or on
the same run loop in multiple modes.
Unless there is a reason to explicitly run it in [NSRunLoop currentRunLoop],
you can remove these two lines:
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
or change the mode to NSDefaultRunLoopMode
NSURLConnection API says " ..delegate methods are called on the thread that started the asynchronous load operation for the associated NSURLConnection object."
Because dispatch_async will start new thread, and NSURLConnection will not pass to that other threat the call backs, so do not use dispatch_async with NSURLConnection.
You do not have to afraid about frozen user interface, NSURLConnection providing only the controls of asynchronous loads.
If you have more files to download, you can start some of connection in first turn, and later they finished, in the connectionDidFinishLoading: method you can start new connections.
int i=0;
for (RetrieveOneDocument *doc in self.documents) {
if (i<5) {
[[NSURLConnection alloc] initWithRequest:request delegate:self];
i++;
}
}
..
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
ii++;
if(ii == 5) {
[[NSURLConnection alloc] initWithRequest:request delegate:self];
ii=0;
}
}
One possible reason is that the outgoing NSURLRequest has been setup to have a -HTTPMethod of HEAD. Quite hard to do that by accident though!
The standard examples I'm seeing in iOS to do a simple GET HTTP connection is to:
NSString *finalURLstring = #"http://www.somesite.com?value=2";
NSURL *url = [NSURL URLWithString:finalURLstring];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *urlConnection = [NSURLConnection connectionWithRequest:request delegate:self];
Then implement these functions:
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
-(void) connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
-(void) connectionDidFinishLoading:(NSURLConnection*)connection
And if you have multiple connections you just create multiple NSURLConnections and compare them in connectionDidFinishLoading:
if (connection == urlConnection1)
// do something
else if (connection == urlConnection2)
// do something else
The issue with this is that you are created a new connection to the server each time right? Is it possible to create your NSURLConnection and reuse it? i.e. keep the connection open so you can make multiple calls instead of creating new connections on every call to the server?
Thanks for your help,
-David
NSURLConnection does that already. It reuses the existing connections.. Check out this accepted answer in
this post. You'll get your answer for your question..
In my iPad application, I want to load a modal window with some data.
But those data can be retrieved from a web service call. So, I have created another class and in that class's connectionDidFinishLoading I can have the response data. As the web service call is asynchronous, I have to wait for the data to load the modal window. Can anyone help me with some example code? Should I think in different way?
Thank you all for the prompt reply.
My problem was solved using the NSNotificationCenter. This tutorial was helpful http://www.youtube.com/watch?v=WB-QCv_4ANU&feature=plcp
Either you can load modal window from connectionDidFinishLoading method. Or you can use delegates to pass data from connectionDidFinishLoading metod to the window that you are going to present. Refer this tutorial.
You start the connection this way:
NSURL *url = [NSURL URLWithString:<#your url string#>];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
myData = [[NSMutableData alloc] init];
con = [[NSURLConnection alloc] initWithRequest:request delegate:self];
And you need to implement NSURLConnectionDelegate delegate.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//append data to your NSMutableData object
[myData appendData: data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
//handle the error
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//here you can use your NSMutableData object, fill your window with the data etc.
<#your code#>
}
This is just an example. You can read more about it in NSURLConnectionDelegate Protocol Reference.
In my iPAD application, I have 6 UITableViews. To get data for each of the tableview, I call a Webservice using NSURLConnection and parse the xml I get back from the Webservice and store data into the database.
Since I have 6 UITableView, I send the Webservice request for each of the views at the same time. However, the problem that I am facing is that, for my app to receive data from the Webservice on the -(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data for 1 table view keeps depending upon the database operations performed by the parsers of the other tableviews.
For example, the webservice request for tableview's A, B, C, D are all sent at the same time. if I get back the data on the -(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data function, until the xml received is parsed and saved to my database, I am not getting the response back for the other tableviews.
I am unable to figure out what I am doing wrong. I know NSURLConnection is asynchronous but the response I am getting does not seem so.
Here is my code -
For sending the Webservice request -
- (void) callMedicationWebService
{
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn)
{
webData = [[NSMutableData data] retain];
}
}
-(void) connection:(NSURLConnection *) connection
didReceiveResponse:(NSURLResponse *) response
{
[webData setLength: 0];
}
-(void) connection:(NSURLConnection *) connection
didReceiveData:(NSData *) data
{
[webData appendData:data];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm:ss"];
NSString *alertMessage = [formatter stringFromDate:[NSDate date]];
[formatter release];
NSLog(#"got data back from WS %#", alertMessage);
}
-(void) connectionDidFinishLoading:(NSURLConnection *) connection
{
[connection release];
// Parse xml
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:[CommonHelper decodeHTMLCharactorsFromString:webData]];
TableAHandler *handler = [[TableAHandler alloc] init];
[handler initTableAHandler];
[xmlParser setDelegate:handler];
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser setShouldProcessNamespaces:YES];
BOOL success = [xmlParser parse];
}
Would someone be able to help me what I am doing wrong?
Asynchronous doesn't necessarily mean that the callback function itself is called in a separate thread.
if you want all the parsing processes to happen at the same time you're gonna have to move the parsing processes to separate threads.
although the better solution would be not to use 5 different URLRequests, and to use only one that returns all the required information.