NSURLConnection, tracking which connection is returning data - objective-c

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.

Related

App not waiting for method to finish executing

I have a method getnamefornumbers which call a soap based web service(sudzc generated), which return a some data which i store in array to use.
But problem is that when i call the method it takes its time to execute and code after this method also executing, this result in null array.
what can i do so when this method completes its work then rest of the code executes.
You have to use custom delegates.You should define the protocol and delegate the current class to responsible for the class which performs getnamefornumbers. Once the operation done , you should return to caller class.
Here is the example of protocols http://mobiledevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
You should use the NSURLConnection delegation methods. In an async environment that's the normal behavior:
You make a call (in an async way)
The application keeps running (after you make the 1. call the program continues with the rest of the instructions)
So you have to two solutions, make it sync, so you will only continue after an answer comes (in your case the array is filled), which I would probably disencourage. Or, you make it async, and use the array when you actually have it.
As for specifics in how to implement this, more details must be provided, in order for me to advise you.
Update 1.0
-(void)requestConnectionToServer{
NSURL *url= [NSURL URLWithString:#"myWebServiceURL"];
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:url];
self.reference=aReference;
[theRequest setHTTPMethod:#"GET"];
[theRequest setTimeoutInterval:20.0];
[NSURLConnection connectionWithRequest:theRequest delegate:self];
}
#pragma mark NSURLConnectionDelegate Implementation
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Response:%#",[[NSString alloc] initWithData:webData encoding:NSASCIIStringEncoding]);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"ERROR with theConenction %#",error);
}
Update 2.0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
myArray = [MyWebServiceAccess getnamefornumbers];
dispatch_sync(dispatch_get_main_queue(), ^{
[myArray makeSomething];
});
});

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.

How to handle different requests using connectionDidFinishLoading in the same delegate?

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

Objective C: Get page content

how to get a web page content from a console application or library? I mean, no UI elemens.
This is what I mean in python
from urllib import urlopen
str = urlopen("http://www.google.com").read()
or php
$str = file_get_contents('http://www.google.com');
or c#
using System.Net;
WebClient client = new WebClient();
string str = client.DownloadString( "http://www.google.com" );
Thanks
NSURLConnection is the class to use in Cocoa, it's usage is pretty straightforward...
Firstly you need to create an instance of NSURLRequest that encompasses the URL you wish to read...
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.stackoverflow.com"]
Create a NSURLConnection to handle your request...
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
Note the second parameter of the init method is a delegate. This delegate needs to implement the following set of methods...
connection:didReceiveResponse:
connection:didReceiveData:
connection:didFailWithError:
connectionDidFinishLoading:
Upon init of the NSURLConnection the download will commence. You can cancel it at any point by send the object a cancel message.
Once you have data to be read the connection will call the connection:didReceiveData: method on it's delegate passing an instance of NSData as the second parameter. This method will be called multiple times as your connection streams you data so use an instance of NSMutableData to aggregate the response...
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[mutableData appendData data];
}
Once the full contents of the URL have been read the connectionDidFinishLoading:(NSURLConnection*) method is invoked. At this point release the connection and use your data.
Check out the documentation for NSURLConnection. This is the asynchronous way to get at it. If you don't mind blocking the thread you can also check out stringWithContentsOfURL:encoding:error: on NSString.
Answer here:
objective c pulling content from website
Just remember to add the framework Webkit

Receive HTTP Headers via NSURLRequest/NSURLConnection in Cocoa

I've been working on figuring out how to receive HTTP Headers via a request made with NSURLConnection. Typically a request is made with something as simple as the following:
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self];
The only way I've personally found in Apple's abundant documentation to receive response headers is via a synchronous call using the following NSURLConnection class method:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
Here I can easily reference a response object of type NSURLResponse. The problem here is that I'm not ready to make synchronous requests via a mobile device, especially with a network that has high latency such as EDGE. Is it possible to get similar results with the default, asynchronous behavior of NSURLConnection?
In your connection delegate, add the -connection:didReceiveResponse: method. If you're doing a standard HTTP request, the NSURLResponse object passed in will actually be an NSHTTPURLResponse object, and responds to the -allHeaderFields message. This should be what you're looking for.