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.
Related
I've made an NSURLConnection, and made a seperate class to be used as a delegate, but I can't make use of the delegates data after the connection has finished. The data writes to console from within the delegate class, but not outside.
In the ServerCommunicationDelegate-class (the delegate), in method "connectionDidFinishLoading":
self.errorLog = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
NSLog(self.errorLog); // Prints the data to console
In the class where the connection takes place:
ServerCommunicationDelegate *del = [[ServerCommunicationDelegate alloc] init];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:del];
NSLog(#"Errorlog %#", del.errorLog); // Returns null
"errorLog" is a property of "ServerCommunicationDelegate".
Is there something I misunderstood about the delegation-paradigm here, or is it maybe something else I've missed?
Either way, thanks in advance.
NSURLConnection works asynchronously. The line
NSLog(#"Errorlog %#", del.errorLog); // Returns null
is executed before the connection has finished loading (probably before it even started
loading).
I know that people have asked this but I have not found satisfactory answers. I have one method that I send all my URLRequests through. I return the response of the request as a string when the method completes. I have recently added ssl to my program. This means that I can no longer use a synchronous request because I need to take advantage of the didReceiveAuthenticationChallenge function as my credentials are currently self-signing. The program needs the response from the URL in order to continue so there is not harm in waiting for the response. However, I cannot seem to find a way to just hold the code up and continue once completed. I can alert the original function that called to request function but I would like the program to pick up right after that call. And it has unique code below such calls so I cannot specialize the connectionDidFinishLoading: function because each method who calls this is different.
How can I pause the program so I can return the nsdata from the connection to the methods that called it?
Here is some pseudo-code to show you what I mean:
- (void) login:(NSString *)username :(NSString *)password {
NSString *str = [NSString stringWithFormat:%#"%#:::%#",username,password];
NSURL *url = [NSURL urlWithString:#"https://blahblahblah"];
NSString *result = [self connectToUrl:str:url];
if ([result isEqualToString:#"valid"]) {
//this would be more complex in here
NSLog(#"hooray");
} else {
NSLog(#"bummer");
}
}
- (NSString *)connectToUrl:(NSURL *)url :(NSString *)str {
NSData *FileData = [str dataUsingEncoding: NSUTF8StringEncoding];
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:100];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
//set up the rest of the request...
...
connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
//WOULD LIKE TO PAUSE HERE UNTIL COMPLETE! THEN CONTINUE
// received data is assigned in didReceiveData: method
return [[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease];
}
But alas, I cannot do this because I cannot make the final line wait until the connection is complete... Please help me!
Very appreciative!
R
iOS and OS X and much of the Cocoa/Cocoa touch frameworks are built on an event model. You don't pause your app. That's not the proper approach. You need to start the connection and then move on. When the connection completes, you act on that event.
In other words, your login method can't sit and wait for the result. It should start the connection and return.
When you get the result of the connection you call some method to process the login result.
Making use of blocks can make things like this easier but there are other ways. You just need to stop thinking about such things in a linear fashion. Dealing with asynchronous processing requires a different approach.
For the iOS app I'm working on, I'm currently writing a singleton class that handles asynchronous requests to a server. Here's an example of one of the methods -
- (void)registerUser:(CBCUserRegistration *)userRegistration delegate:(id)<CBCUserRegistrationDelegate>delegate;
within this method, an NSURLConnection is created and sends an asynchronous request. At this point, i need a way to tie the delegate object to the NSURLConnection, so thats when
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
is called, I know which delegate to inform. Because the requests are asynchronous, there may be more than one request going at any time. My initial though was to use an NSMutableDictionary, setting the NSURLConnection as the key and the delegate as the value, but the keys are copied so thats a no go. Can anyone suggest another way to track this?
Thanks in advance.
Avoid using an NSDictionary for this. Instead take an object-oriented approach:
Write a class MyConnection that implements the required NSURLConnectionDelegate callbacks and has a property/ivar of the id<CBCUserRegistrationDelegate>type. Add a start method to MyConnection that creates an NSURLConnection, assigns itself a delegate of that connection, and starts it. Now you can create an instance of MyConnection for every URL request you do. MyConnection keeps hold of the CBCUserRegistrationDelegate and forwards the result it receives from the NSURLConnection.
However, using delegate here is a bit old-fashioned. Use blocks instead, especially if your project uses ARC. NSURLConnection provides a convenient method to do async requests: [NSURLConnection sendAsynchronousRequest:queue:completionHandler:].
For example:
- (void)registerUser:(CBCUserRegistration *)userRegistration delegate:(id<CBCUserRegistrationDelegate>)delegate
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://mysite.com/register"]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
[delegate processRegistrationResponseData:data];
}];
}
Use a NSNumber set to the address of the NSURLConnection as the key, and then you can set another dictionary as the object of the key. You can give it a name, etc, record the object to notify etc. Just remember to remove it when the NSURLConnection is released.
Whenever I do a curl call using the below code:
NSURL *url = [NSURL URLWithString:requestURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
if (connectionInProgress) {
[connectionInProgress cancel];
}
connectionInProgress = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
connectionDidFinishLoading is my final destination where I can manipulate the response data and call my next methods to continue with the app . If I hard-code some specific tasks like
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
[parser setDelegate:self];
[parser parse];
[someLabel setText:parsedTextFromXMLData];
}
If I need to do another curl call to a different address, wouldn't someLabel setText always get re-set again? Is there a way to make this delegate function behave differently on each curl call? (btw, is connectionDidFinishLoading usually the right place to put the next step of codes?) If so then wouldn't it always get called again by the next curl call?
Have a look at this S.O. post for a recipe concerning NSURLConnection and multiple requests.The suggestion is doing something like this:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == firstConnection) {
// do something
}
else if (connection == secondConnection) {
// do something else
}
}
EDIT: the idea here is that connectionDidFinishLoading is a method of your own delegate (so you write it). In the delegate, you store the address of each connection you create; then, when the connection comes back with the data, you tell which connection it is by comparing its address to the one you stored in the delegate. -END EDIT
Another option you have is using the ASIHTTPRequest framework, which offers a request-based (as opposed to connection-based) delegation mechanism, so each request has got a delegate object to handle the result; or, in other words, the delegate receives a reference to the request, so you can easily tell which request result you are handling.
ASIHTTPRequest offers a bunch of advantages over NSURLConnection. You can read about them in this S.O. post.
There're 2 options to do this:
you can implement a separate class, that will be responsible for handling NSURLConnection delegate stuff and create a separate instance for each request
you can use NSObject key-value methods on NSURLConnection instance for setting up some tag, that will be checked in connectionDidFinishLoading: method
For me, option 1 will be a better approach
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