Return data from NSURLConnection delegate method
Here is the situation. I am sending my AppDelegate a Notification to update some data within itself. The AppDelegate then calls a class method which was initially set to return a Dictionary from my server synchronously. I change the code around inside the class method so now it uses NSURLConnection to asynchronously get data from my server. So I put the original return data into the delegate method - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data.
My question is now, how do I return the Dictionary from that delegate method back to my AppDelegate?
There are three ways to pass data between objects in cocoa.
1) Directly. The sender has a pointer to the receiver and knows which method to call
2) Notification. The sender broadcasts and the reciever listens
3) Bindings. The sender and receiver both have a binding to the same value
Directly is the simplest and in your case here, it's probably very simple to use the following technique:
Controller.mm
#include stuff
MyController* myController ;
// your async call back is here somewhere
... didReceiveData :(NSData) data
{
NSDict* dict ........ ;
[myController heresTheDictionaryBuddy:dict] ;
}
@implementation Controller {
- (void) heresTheDictionaryBuddy:(NSDictionary*) theDict
{
// do the business
[theDict retain];
[myDict release] ;
myDict = theDict ;
}
- (void) awakeFromNib
{
myController = self ;
}
@end
If your async call back code is in a different .m/.mm file, you can declare extern Controller* myContoller ; in a shared .h file and the linker will take care of the rest.
////
Here's another simple direct way:
I don't remember using the classes that you mentioned, however with most of those things, there is an id contextInfo you can pass. So when you "fire" the async event, you can do something like:
myConnections:@"url" ..... context: self
In the receiver, you can do:
Controller* controller = (Controller*) context ;
[controller heresTheDictionaryBuddy:dict];
Perhaps it will be easier to show you my code to get a better idea. If this bad code, don't blame me, I inherited it.
My AppDelegate function in which I want to get a return value
- (BOOL)autoLoginWithUserName:(NSString *)username andPassword:(NSString *)password {
self.appointmentsForDate = [[NSMutableArray alloc] init];
NSArray *keys = [NSArray arrayWithObjects:@"username", @"password", @"appID", nil];
NSArray *objects = [NSArray arrayWithObjects:username, password, @"1", nil];
NSDictionary *parameters = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *wsResponse=[WebServices callRestService:@"loginUser" withParameters:parameters]; <-----This is were I require a return value from the class method, so I would have to continue from
here to go through the validation process
NSString *responseString = [wsResponse objectForKey:@"value"];
if (responseString) {
XMlParser *xmlParser = [[[XMlParser alloc] init] autorelease];
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding]] autorelease];
[parser setDelegate:xmlParser];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
NSDictionary *resultDictionary = xmlParser.parentElement;
NSArray *elementArray = [resultDictionary objectForKey:@"elementData"];
NSDictionary *attributesDict = [elementArray objectAtIndex:1];
NSString *response = [attributesDict objectForKey:@"result"];
if ( [response compare:@"Fail"] == NSOrderedSame) {
return NO;
}
else {
[[NSUserDefaults standardUserDefaults] setObject:username forKey:@"username"];
[[NSUserDefaults standardUserDefaults] setObject:password forKey:@"password"];
[[NSUserDefaults standardUserDefaults] setObject:[attributesDict objectForKey:@"userid"] forKey:@"userid"];
BOOL selected = [[attributesDict objectForKey:@"User"] boolValue];
[[NSUserDefaults standardUserDefaults] setBool:selected forKey:@"Enabled"];
[functions dismissModalViewControllerAnimated:YES];
[self getAppointmentsForDate];
return YES;
}
}
else {
UIAlertView *error = [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Could not connect to server" delegate:nil cancelButtonTitle:@"Retry" otherButtonTitles:nil] autorelease];
[error show];
return NO;
}
return NO;
}
This is where I initially would get my value from, but I want to make it asynchronous.
+(id)callRestService: (NSString *) methodName withParameters:(NSDictionary *) parameters
{
NSURLRequest *url=[WebServices getRestUrl: methodName withParameters: parameters];
XMlParser *xmlParser = [[[XMlParser alloc] init] autorelease];
NSXMLParser *parser = [[[NSXMLParser alloc] initWithContentsOfURL:[url URL]] autorelease];
if (parser) {
[parser setDelegate:xmlParser];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
return xmlParser.parentElement;
}
return NO;
}
Routers
Thanks for the code - it looks fine (although I suspect it's leaking memory). I'm at work now (in California). I'll have to leave this until I get home this evening - however I promise I will reply.
Never mind, I am going to keep that code. There was a problem in communication, so I thought I need to update this code.
OK. I'm happy to be off the hook. However I have written a little program httpget which does an async http get request and display progress and output. http://clanmills.com/articles/cocoatutorials/httpget.zip
Usual guarantees and excuses. I know the code leaks memory, but what the heck, I've had a long day in the office.