iPhone NSURLConnection - delegates not working - iphone

I am trying to get an NSURLConnection to work in my app. I have followed apple's code almost exactly but it doesn't seem to work. The NSURLConnection is inside of a method called, downloadSave. This method runs properly through the end, and my log indicates, "Connection Exists" - however nothing happens after that as if none of the delegate methods get called.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString *tempString = [[NSString alloc]initWithFormat:#"http://www.myWebsite.com/%#.jpg",chartFileName];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:tempString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
mutableData = [[NSMutableData data] retain];
self.image = nil;
NSLog(#"connection exists");
} else {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Connection Error" message:#"There was an error contacting the servers. Please try again." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
[activityIndicator stopAnimating];
}
[pool drain];
[pool release];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"got to connection did receive response");
[mutableData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mutableData appendData:data];
NSLog(#"got some data were at %i",mutableData.length);
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[connection release];
// receivedData is declared as a method instance elsewhere
self.mutableData = nil;
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[mutableData length]);
//more code follows to display the downloaded image
}
The only thing that appears in the log is: "Connection Exists"

I can only guess by your code that downloadSave in called in a separate thread as you have an NSAutoReleasePool (not saying thats what your doing but its likely). NSURLConnection can only respond to the delegate methods in the main thread when it is initialised in the main thread.
As NSURLConnection already is a threaded delegate call you shouldn't need to create it in thread. If you need to thread it for some reason you should be able to use
NSError *error;
NSURLResponse *response;
NSData *connectionData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
And that should return the data to the child thread.

Related

NSURLConnection doen't return data where dataWithContentsOfURL does

I have an application and I used to get my json data with dataWithContentsOfURL.
But because I need to get it an asynchrone fashion.
Now that I use NSURLConnection to handle this I don't receive any useful data all I get is statuscode 200 in the didReceiveResponse method but didReceiveData is never called.
And at connectionDidFinishDownloading destinationURL returns null.
I have no idea wat couses this problem and I would really appreciate some help.
the delegate
#import "NetWorkToGuiDelegate.h"
#implementation NetWorkToGuiDelegate
#synthesize data;
#synthesize caller;
- (id) init: (SEL) pointer :(NSObject *) c;
{
doWhenDone = pointer;
self.caller = c;
data = [[NSMutableData alloc]init];
return self;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *responseText = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
NSLog(#"%#",responseText);
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
{
NSLog(#"post download finished");
data = [NSData dataWithContentsOfURL:destinationURL];
NSLog(#"data: %#",data);
NSLog(#"URLconnection %#", connection.currentRequest);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[caller performSelector:doWhenDone withObject:data];
#pragma clang diagnostic pop
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.data setLength:0];
NSHTTPURLResponse *resp= (NSHTTPURLResponsae *) response;
NSLog(#"got responce with status %d",[resp statusCode]);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d
{
NSLog(#"data recieved %#",d);
[self.data appendData:d];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error", #"")
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", #"")
otherButtonTitles:nil] show];
NSLog(#"failed");
}
// Handle basic authentication challenge if needed
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString *username = #"username";
NSString *password = #"password";
NSURLCredential *credential = [NSURLCredential credentialWithUser:username
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
#end
the call
NetWorkToGuiDelegate *nwgd = [[NetWorkToGuiDelegate alloc] init:#selector(login:) :self];
NSString *stringURL = [NSString stringWithFormat:#"%#%#%#%#", dk.baseURL, #"menu?code=",dk.loginCode,#"&v=1"];
NSURL *url = [NSURL URLWithString:stringURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:nwgd];
[urlConnection start];
I'll just add that the call happens on the main thread
Actually there is a lot of points to make the answer of this question and there are so many questions on SO itself
Go through this nice post
And a must Read doc from apple itself.(contains code samples and explanations)
Hope this will solve the problems for you.
EDIT
-(void)startAConnection
{
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.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.
receivedData = [NSMutableData data];
} 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
{
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
}
Call startAConnection to start the process
NOTE: Don't forget <NSURLConnectionDelegate> in the .h

NSURLConnection returns data but I cannot read it

This is another simple question who'se answer escapes me after a hour on Google...
A user is typing something into a text field and upon this field loosing focus, I launch an NSURLConnection....
NSString *usernameTry = [sender text];
NSLog(#"username field = %#",usernameTry);
NSString *content = [#"http://www.siebenware.de/Rhythm/user/checkusername.php?username=" stringByAppendingString:usernameTry];
content = [content stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:content] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:5.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
NSLog(#"%#",content);
Then I wait for the response....
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Received Response");
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
int status = [httpResponse statusCode];
if (!((status >= 200) && (status < 300))) {
NSLog(#"Connection failed with status %#", status);
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[resultsData appendData:data];
NSString *resultsString = [[NSString alloc] initWithData:resultsData encoding:NSUTF8StringEncoding];
NSLog(#"received data %# %i",resultsString,[resultsString length]);
if ([resultsString isEqualToString: #"FAIL"]){
NSLog(#"failed to retrieve data");
}else{
resultsObjects = [[resultsString componentsSeparatedByString:#":"] mutableCopy];
if([resultsObjects objectAtIndex:0]==#"usernamecheck"){
if ([resultsObjects objectAtIndex:1]==username.text) {
if ([resultsObjects objectAtIndex:2]==#"NG"){
//set the check marker to bad
[usernameVer setImage:[UIImage imageNamed:#"redcross.png"]];
}else{
//set the check market to good
[usernameVer setImage:[UIImage imageNamed:#"greentick.png"]];
}
}
}
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog([NSString stringWithFormat:#"Connection failed: %#", [error description]]);
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:#"Unable to retrieve data" message:[NSString stringWithFormat:#"Error code %i",[error code]] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
}
I see the response arrive in didReceiveResponse and am getting 18 bytes of data (which is correct).
However didReceiveData says that the 'data' is null. I know I am missing something exceptionally simple, and I promise to kick myself once this is cleared up.
Regards
Chris H
if you want to change the data into an NSString you can do this:
NSString *responsestring = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#", responsestring);
You need work with your data in:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
Because
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
can be called many times
You can do that:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[myData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// TODO: work with data
}
NSMutableData* myData must be instance var.
You need to convert the NSMutableData received by the NSURLConnection delegate method to readable NSString by using the below code
NSString *finalString = [[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding];
and that should do it.
Try with other encoding..May be ASCII encoding instead of UTF-8..It may work out

NSUrlConnectionDelegate not calling methods to load data

I have looked at NSURLConnectionDelegate connection:didReceiveData not working already, but there didn't seem to be any good result from that, so I am curious why I am not able to get any data.
I put in breakpoints in didReceiveResponse and didReceiveData.
It does print out "connection succeeded", so I know that the connection is started.
I am using ARC for memory management.
- (void)load {
request = [NSMutableURLRequest requestWithURL:myURL
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (conn) {
[conn start];
NSLog(#"connection succeeded, %s", [myURL description]);
responseData = [NSMutableData data];
} else {
NSLog(#"connection failed");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
UPDATE:
To see how I test this look at Asynchronous unit test not being called by SenTestCase.
I did implement the two methods mentioned by jonkroll, in his answer, I just didn't show them, but, they also aren't being called.
I had added [conn start] only because it wasn't working, and I was hoping that may solve it, but no such luck.
When you declare your connection like this:
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
You are creating a local pointer. When your method completes, since it was the last strong reference to the NSURLConnection, ARC releases it. You need to use a strong ivar (and/or) property to hold a strong reference to the NSURLConnection you create.
Edit
Here is basic sample of code that I tested in a sample project. Give it a run. Verbose logging helps.
#implementation <#Your class here#> {
// With ARC ivars are strong by default
NSMutableData *_downloadedData;
NSURLConnection *_connection;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse *realResponse = (NSHTTPURLResponse *)response;
if (realResponse.statusCode == 200){
// Really any 2** but for example
_downloadedData = [[NSMutableData alloc] init];
NSLog(#"Good response");
} else {
NSLog(#"Bad response = %i",realResponse.statusCode);
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
if (connection == _connection){
[_downloadedData appendData:data];
NSLog(#"Getting data...");
}
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
if (connection == _connection){
_connection = nil;
NSLog(#"We're done, inform the UI or the delegates");
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
_connection = nil;
NSLog(#"Oh no! Error:%#",error.localizedDescription);
}
- (void)load {
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60];
// Assign strong pointer to new connection
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"Connection was initialized? = %#",(!!_connection)?#"YES":#"NO");
}
#end
The NSURLConnection method initWithRequest starts an asynchronous request for data from a url. Because the request is done asynchronously you can't expect to work with the response in the same method in which the request is invoked. Instead you need to do so in the NSURLConnection's delegate callback methods. You have already implemented didReceiveResponse: and didReceiveData:, but there are a couple others that will be useful to you.
If you want to look at the contents of the response you should do so in connectionDidFinishLoading:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// response is complete, do something with the data
NSLog(#"%#", responseData);
}
The fact that your code prints out "connection succeeded" doesn't really mean that the request was successful, only that the NSURLConnection object was created successfully. To test whether there was a problem with the connection you can implement the delegate method connection:didFailWithError:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
Also there is no need to call [conn start]. The request will be started automatically when you call initWithRequest:
I suggest reading Apple's documentation on Using NSURLConnection for more details.

Get URL File Size before parsing

Me again! I am using NSURL to get a file then parse it. I have been looking for a couple of hours now on a progressbar i am trying to implement in my app. I know I first need to get the file size, then keep updating how much data i've downloaded as I continue to pull. I have seen the example using "ASIHTTPRequest" but is there a way to do it with what I already have?
Here is where I start the download.
-(void)parseNewData {
//start network activity spinner and release controller when done
parserDone = NO;
[root downloadIcon];
//create pool to avoid memory leak
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// get the XML path and start parsing
NSURL *pathURL = [NSURL URLWithString:#"http://www.mysite.com/myfile.xml"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:pathURL];
[parser setDelegate:self];
[parser parse];
//drain pool
[pool drain];
[pool release];
}
Can someone point me in the right direction on how to get file size, then how to update how much I've downloaded. Thanks in advance!
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength: 0];
CGFloat size = [[NSString stringWithFormat:#"%lli",[response expectedContentLength]] floatValue];
NSLog(#"Size : %f",size);
}
Above code will give you total size
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
totalDownloadedData += [data length]; // global integer
NSLog(#"Status : %d/%f",totalDownloadedData,size);
}
Above code will show you current status of downloading
You need to use NSURLConnection if you want to get the file size and the progress. You get delegate methods which you can use to monitor progress. The didSendBodyData: delegate method tells you how much data there is in bytes. The connectionDidFinishLoading is where you uget receivedData to use in your NSXMLParser code.
NSURLRequest *theRequest = [NSURLRequest requestWithURL:URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [[NSMutableData data] retain];
}
}
- (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 didFailWithError:(NSError *)error{
// release the connection, and the data object
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
}
- (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 didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite{
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{

iPhone - SSL connection

What is the best starting point to learn connecting to ssl web services by iphone?
Until now i did some basic connections over http via SOAP etc. but i have no experience on https. Any good sources, tutorials, starting references, "use nsurl...class"s are appreciated
NSURLConnection works by default with SSL and can access https sites. Issues may appear regarding letting user trust SSL certificates, here's a discussion on this that I've found to be interesting.
i'm posting a sample https client. it ignores if server certificate is not valid.
the server has a webget method with uritemplate=username({usercode})/password({passcode})
you can use CharlesProxy to check your outgoing message
#import "Hello_SOAPViewController.h"
#interface NSURLRequest (withHttpsCertificates)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
#end
#implementation Hello_SOAPViewController
NSMutableData *webData;
- (void)viewDidLoad {
//////////////////////////////////////////////////
//Web Service Call
//////////////////////////////////////////////////
NSURL *url = [NSURL URLWithString:#"https://192.168.1.105/HelloService/Service.svc/username(user)/password(xxx)"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
[theRequest addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[theRequest setHTTPMethod:#"GET"];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(theConnection) {
webData = [[NSMutableData data] retain];
}
else {
NSLog(#"theConnection is NULL");
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR with theConnection:%#",[error description]);
if ([error code] == -1001 ){//isEqualToString:#"timed out"]) {
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:#"Connection Error" message:#"Server Unresponsive" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alertView show];
}else{
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:#"Connection Error" message:#"Check your internet connection " delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alertView show];
}
[connection release];
[webData release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"DONE. Received Bytes: %d", [webData length]);
///////////////////////
//Process Your Data here:
///////////////////////
[connection release];
[webData release];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
Check out ASIHTTPRequest. It is very stable, non-leaky, easy-to-use and includes a bunch of goodies like download file resuming, progress bar support etc… It also has authentication support