ASIHTTPRequest delegation - ios

im using ASIHTTPRequest to call webservice (soap):
-(void)callWebService:(NSString*)URL:(NSString*)SOAP{
NSURL *url = [NSURL URLWithString:URL];
NSString *SOAPMessage = [NSString stringWithFormat:SOAP];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
request.shouldAttemptPersistentConnection = NO;
[request setValidatesSecureCertificate:NO];
[request setRequestMethod:#"POST"];
[request appendPostData:[SOAPMessage dataUsingEncoding:NSUTF8StringEncoding]];
[request setDidFinishSelector:#selector(requestCompleted:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request setDelegate:self];
[request startAsynchronous];
}
-(void)requestCompleted:(ASIHTTPRequest * )r{
NSString *responseString = [r responseString];
NSLog(#"%#",responseString);
}
-(void)requestFailed:(ASIHTTPRequest * )r{
NSError *Err = [r error];
NSLog(#"%#",Err);
}
If i call this in appDelegate.m, it works fine, requestCompleted handler throws the response...But when i use this same code in my own class it throws BAD ACCESS error, which i figured tells me i cannot delegate:self to handle response. if i setDelegate to appdelgate pointer (passed as ID sender) it works (and have handlers there). So why cant my own class handle its own events ? Im new to objective-c so i guess im missing something major here. Thanks

You have to have the requestCompleted and requestFailed in your "own class". Also that class has to live which means it can't be released while the service is being called. You have to save the instance of "your own class" in a strong/retained property or something.

Add this code to dealloc or viewWillDisappear
[request setDelegate:nil];

Check if your self is getting released while the delegate call happens. Make sure it is retained properly.

Related

Consume ASP web service with JSON response on iOS

I am trying to call a web service that is developed with ASP.NET. The purpose is to pass a username and password to the web service to simulate a log-in procedure.
In order to call the service i used the following method:
NSError *errorReturned = nil;
NSString *urlString = #"http:myDomain/myMethod?Operation=SignIn";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod: #"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"test" forKey:#"userName"];
[dict setObject:#"test" forKey:#"passWord"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&errorReturned];
[request setValue:[NSString stringWithFormat:#"%d", [jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: jsonData];
NSURLResponse *theResponse =[[NSURLResponse alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&errorReturned];
if (errorReturned)
{
NSLog(#"%#", errorReturned);
}
else
{
NSString *retVal = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", retVal);
}
After running the app and clicking on the UIButton that fires the above method, nothing is shown in the console window.
The service returns the response in JSON format.
I want to know if i am missing something here since i am neither getting an error nor success log?
Any help would be appreciated!
Thank you.
Granit
A couple of thoughts:
If this method is getting called, you'd see something, even if retVal was empty and your
NSLog(#"%#", retVal);
just logged the app name and timestamp. Maybe change that NSLog to
NSLog(#"retVal = %#", retVal);
to remove any ambiguity. Or put in breakpoints in your code and single step through it to see what path the app takes.
Are you confident of your server interface? For example, is it possible that the Operation value of SignIn belongs in the JSON request, itself? Also, some services are case sensitive, so you might want to check that, too.
I don't know what access you have to the server, but it would be worthwhile to check the logs to make sure the request was received, possibly temporarily adding some logging within the code so you can confirm that the parameters were all received properly. Or, if nothing else, make sure that the server properly logs/reports any errors.
BTW, your instantiation of theResponse is unnecessary, and should just be
NSURLResponse *theResponse = nil;
The sendSynchronousRequest call doesn't populate an existing NSURLResponse instance, but rather creates a new instance and updates theResponse to point to it.
You should fix your request first, but you probably want, at the very least, to change this to use sendAsynchronousRequest instead of sendSynchronousRequest. You should never do synchronous calls on the main thread.
I solved my issue by using ASIHHTPRequest. Also i checked the server interface and it turned out that the parameters had to be sent with the URL.
-(void)signInAction:(id)sender{
NSURL *url = [NSURL URLWithString:#"http://mydomaain.com/UserService/SignIn/test/test"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDidFinishSelector:#selector(requestCompleted:)];
[request setDidFailSelector:#selector(requestError:)];
[request setDelegate:self];
[request setRequestMethod:#"GET"];
[request startAsynchronous];
}
- (void)requestCompleted:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
//[responseString UTF8String];
NSLog(#"ResponseString:%s",[responseString UTF8String]);
}
- (void)requestError:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Error:%#",[error description]);
}

Application UI hangs due to networking , iOS

I am developing an iOS application where i am implementing push notifications.
In the AppDelegate and more specifically in the didRegisterForRemoteNotificationsWithDeviceToken function , after i register for push notifications , i make an http post request to send to my server the users credentials (cfuuid , os , etc..) and the push token.
When the server is app everything goes smoothly. However , if for any reason the server is unreachable the UI of the application hangs for around 30 seconds (till the connection timeOut) and the only thing i see is a white screen.
How could i separate the "networking" from the UI ? I guess the answer is by using another thread.
How exactly could i do that ? The only thing i am doing inside the didRegisterForRemoteNotificationsWithDeviceToken is use ASIHTTPRequest library to send the credentials to the server.
The code that needs to be executed in the different thread looks like this :
NSString *jsonString;
//jsonString = [[NSString alloc] initWithFormat:#"{\"deviceUUID\":\"%#\",\"os\":\"ios\", \"active\":\"%d\", \"pushToken\":\"%#\"}",deviceUUID,active,token];
jsonString = [[NSString alloc] initWithFormat:#"{\"deviceUUID\":\"%#\",\"os\":\"ios\", \"pushToken\":\"%#\"}",deviceUUID,token];
NSLog(#"%#",jsonString);
//NSString *urlStr= [[NSString alloc] initWithFormat:CITYINFO_SERVER_URL,#"push_notifications/register"];
NSString *urlStr= [[NSString alloc] initWithFormat:CITYINFO_SERVER_URL,#"register.php"];
//send json file , using ASIHttpClass
NSURL *url = [NSURL URLWithString:urlStr];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
request.timeOutSeconds = TIME_OUT_SECONDS;
[request setRequestMethod:#"PUT"];
//NSString *credentials= [self encodeCredentials];
//[request addRequestHeader:#"Authorization" value:[[NSString alloc] initWithFormat:#"Basic %#",credentials]];
[request addRequestHeader:#"Content-Type" value:#"application/json; charset=utf-8"];
[request appendPostData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[request startSynchronous];
if([request responseStatusCode]==200){
NSLog(#"Server reached. Response Status : 200");
return true;
} else {
NSLog(#"Server could not be reached");
return false;
[request startSynchronous];
Never. Do. Synchronous. Networking. On the main thread.
Move it to another thread, or even better, make the request async.
Instead of sending a synchronous request just send Asynchronous request
[request startAsynchronous];
And call the method which is hitting service after some time interval from delegate method.
use [request startAsynchronous];
instead of [request startSynchronous];
I think , you are use main thread for send device token to server,please use the secondary thread for this functionality
try this code :-
[self performSelectorInBackground:#selector(pushNotifictionJson) withObject:nil];
-(void) pushNotifictionJson
{
NSString *jsonString;
//jsonString = [[NSString alloc] initWithFormat:#"{\"deviceUUID\":\"%#\",\"os\":\"ios\", \"active\":\"%d\", \"pushToken\":\"%#\"}",deviceUUID,active,token];
jsonString = [[NSString alloc] initWithFormat:#"{\"deviceUUID\":\"%#\",\"os\":\"ios\", \"pushToken\":\"%#\"}",deviceUUID,token];
NSLog(#"%#",jsonString);
//NSString *urlStr= [[NSString alloc] initWithFormat:CITYINFO_SERVER_URL,#"push_notifications/register"];
NSString *urlStr= [[NSString alloc] initWithFormat:CITYINFO_SERVER_URL,#"register.php"];
//send json file , using ASIHttpClass
NSURL *url = [NSURL URLWithString:urlStr];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
request.timeOutSeconds = TIME_OUT_SECONDS;
[request setRequestMethod:#"PUT"];
//NSString *credentials= [self encodeCredentials];
//[request addRequestHeader:#"Authorization" value:[[NSString alloc] initWithFormat:#"Basic %#",credentials]];
[request addRequestHeader:#"Content-Type" value:#"application/json; charset=utf-8"];
[request appendPostData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[request startSynchronous];
if([request responseStatusCode]==200){
NSLog(#"Server reached. Response Status : 200");
return true;
} else {
NSLog(#"Server could not be reached");
return false;
}
}
and second method
use [request startAsynchronous];
instead of [request startSynchronous];

Create iOS client server app. ASIFormDataRequest issues

My question is:
How can I create the same request as below using ASIFormDataRequestand second as I think I need to parse JSON from response.
http://exampledomain.com/mobile_api/register/?client=iphone&info=A=iPhone/OS=5.1/C=UA&time=1342780143&udid=8b6f0cc104d137ae2e1730235f5664094b831122&version=1.0&secure=5444d72741bad93b916577d9297fa
Now I try to use code like this
NSString *strURL = #"http://test2.mafia.ua/mobile_api/register/";
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:strURL]];
[request setDelegate:self];
[request setPostValue:#"iphone" forKey:#"client"];
[request setPostValue:#"A=iPhone/OS=5.1/C=UA" forKey:#"info"];
[request setPostValue:#"1342780143" forKey:#"time"];
[request setPostValue:#"8b6f0cc104d137ae2e1730235f5664094b831122" forKey:#"udid"];
[request setPostValue:#"1.0" forKey:#"version"];
[request setPostValue:#"5444d72741bad93b916577d9297fa" forKey:#"secure"];
[request startAsynchronous];
is this correct?
I implement delegate method also
- (void)requestFinished:(ASIHTTPRequest *)request {
NSLog(#"Response %d ==> %#", request.responseStatusCode, [request responseString]);
}
- (void)requestFailed:(ASIHTTPRequest *)request {
}
In response I get this (I think this is JSON) if I use some browser.
{"status": "ok", "secret": "b82b7771f600772c2c5af903b117b5e", "client": "200004", "expires": "1345372850"}
You're passing your data in POST fields (That's what setPostValue: does.)
You should be including them in your URL instead; try searching around for an easy way of building query parameters in a URL or just use something like stringWithFormat: and appropriate escaping.

ASIHTTPRequest Get Request - Delegate Not Getting Called

My request is
NSURL *requestUrl = [NSURL URLWithString:url];
if(request_) {
[request_ setDelegate:nil];
[request_ release];
}
request_ = [[ASIFormDataRequest requestWithURL:requestUrl] retain];
[request_ setDelegate:self];
[request_ setRequestMethod:#"GET"];
[request_ setTimeOutSeconds:HTTP_TIME_OUT];
[request_ startAsynchronous];
The call is going since the network access indicator on the top bar is rotating and disappearing after a few seconds. But either of the delegate methods
- (void)requestFinished:(ASIHTTPRequest *)request
or
- (void)requestFailed:(ASIHTTPRequest *)request
is not being called. What could have went wrong?
Thanks in advance.
PS: Sometimes, due to some issue, server is returning a "500 Internal Server Error". But even in that case, shouldn't the delegate
- (void)requestFailed:(ASIHTTPRequest *)request
be called?
you can use the blocks to check that out.
here is the example of the same:
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
}];
[request setFailedBlock:^{
NSError *error = [request error];
}];
[request startAsynchronous];
I hope this might help.
Make sure your class is conforming to the ASIHTTPRequestDelegate protocol.
#interface YourClass : ... <ASIHTTPRequestDelegate>

Passing an object into a ASIHTTPRequest block

OK. I'm not completely clear about blocks, but I do use them often; especially when doing an ASIHTTPRequest. I'd like to pass an object into the block and have the request assign a value to the object on completion, but I don't know how to make the object 'available' inside a block.
Here's my method...
- (void)fetchImageAsynchronously:(NSURL *)theURL intoImageObject:(UIImage *)anImageObject
{
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:theURL];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[request setCompletionBlock:^{
NSData *responseData = [request responseData];
anImageObject = [UIImage imageWithData:responseData];
}];
[request setFailedBlock:^{
// NSError *error = [request error];
}];
[request startAsynchronous];
}
So, when the request completes, I want the value of anImageObject to be the fetched image. But anImageObject is not available inside the block.
Would someone kindly help?
anImageObject would have to be passed by reference. That is, UIImage**, and pass the address of anImageObject when calling the method.
This isn't a great design because you'll also have to manage the lifetime of anImageObject and also likely post some sort of notification that it is ready. That is, this code will break if anImageObject is deallocated in the time that it takes to download the image data. And you wont know that anImageObject was initialized with data or not.
- (void)fetchImageAsynchronously:(NSURL *)theURL intoImageObject:(UIImage **)anImageObject
{
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:theURL];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[request setCompletionBlock:^{
NSData *responseData = [request responseData];
*anImageObject = [UIImage imageWithData:responseData];
}];
[request setFailedBlock:^{
// NSError *error = [request error];
}];
[request startAsynchronous];
}

Resources