Both setCompletionBlock and setFailed don't get called - iphone

I'm getting acquainted with ASIHTTPRequest library and i tried to implement connection to a server. Here is my code:
- (BOOL)IsEnteredDataCorrect {
__block NSString *password;
__block NSString *responseString;
NSString *url = [NSString stringWithFormat:#"%#/login/",SERVER_URL];
__block ASIHTTPRequest *loginRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.labelText = #"Please wait";
[loginRequest setCompletionBlock:^
{
[MBProgressHUD hideHUDForView:self.navigationController.view animated:YES];
responseString = [loginRequest responseString];
// NSLog(#"%#",responseString);
NSData *responseData = [loginRequest responseData];
NSError *err = nil;
NSDictionary *users = [[CJSONDeserializer deserializer] deserializeAsDictionary:responseData error:&err];
password = [users objectForKey:idField.text];
}];
[loginRequest setFailedBlock:^
{
[MBProgressHUD hideHUDForView:self.navigationController.view animated:YES];
[delegate alertError:[loginRequest error]];
NSLog(#"failed block");
}];
[loginRequest startAsynchronous];
NSLog(#"request is over");
if ([password isEqualToString:passwordField.text])
return YES;
else
return NO;
}
The server name is fake so i expected setFailedBlock to get called. But strange thing happens: MBProgressHUD is taken away (it is possible only when one of the blocks is called) but the code in setFailedBlock is not executed. The further code is executed successfully. OK, setFailedBlock doesn't work - but then MBProgressHUD should stay on the screen and it's gone. Can anyone explain me what's going on?

If your failed block isn't running but the MBProgressHUD is vanishing then your completion block is running.
Perhaps your server name isn't as fake as you think it is? There's an awful lot of weird domain names registered...
Also, your code here:
[loginRequest startAsynchronous];
NSLog(#"request is over");
if ([password isEqualToString:passwordField.text])
return YES;
else
return NO;
You seem to have a fundamental mismatch here - your are using an asynchronous request, but appear to be expecting that the answer is there immediately.

Related

How to avoid delay of webservice(ASIHTTPRequest) response in iPhone?

In my iPhone app handling web service for storing and retrieving data.Now i am using the following code for web service handling.
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"1" forKey:#"id"];
[request setTag:100];
[request setDelegate:self];
[request startAsynchronous];
By this code i got response in 'requestFinished' method.My problem is web service response is very delay(depends upon internet speed).How to make response from web service very fast?Please help me.
I think you want to send json objects by post method..delay is depend on your server(how fast it handle request and response back) but i suggest you to use progress bar and blocks to handle network request..
loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.labelText = NSLocalizedString(#"Downloading", nil);
loadingHUD.mode=MBProgressHUDModeAnnularDeterminate;
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject];
// Add your filename to the directory to create your saved file location
NSString* destPath = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
NSURL *url = [NSURL URLWithString:mainURL];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:postURL parameters:postRequest];
NSLog(#"postRequest: %#", postRequest);
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:destPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Successfully downloaded file to %#",[[NSString alloc] initWithData:operation.responseData encoding:NSASCIIStringEncoding]);
// Give alert that downloading successful.
NSLog(#"Successfully downloaded file to %#", destPath);
NSLog(#"response: %#", operation.responseString); // Give alert that downloading successful.
// [self.target parserDidDownloadItem:destPath];
loadingHUD.detailsLabelText = [NSString stringWithFormat:#"%# %i%%",#"Downloading",100];
[loadingHUD hide:TRUE];
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Give alert that downloading failed
NSLog(#"Error: %#", error);
// [self.target parserDidFailToDownloadItem:error];
[loadingHUD hide:TRUE];
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
{
// Progress
progress = ((float)totalBytesWritten) / fileSize;
loadingHUD.progress = progress;
}];
[operation start];
}
We cant control the internet speed due to the different network provider or environment when the client is using your app.
But you can put your web-services to run in background without effecting your main function.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//code for webservices calling
dispatch_async(dispatch_get_main_queue(), ^{
//functions after your webservices done, for example reload the table or hide the loading bar.
});
});

how to display progress bar while downloading file from request response in Asihttp

I am downloading video file from response.
i want to display downloading progress bar of HUD-progress.
but how can i do that.
I am sending verify json to server and server verify that send back the video file bytes. i want to display how much percentage of downloading is done by using HUD-progreasse bar.
If i call [request setDidReceiveDataSelector:#selector(request:didReceiveBytes:)]; than it display how much bytes i got but it doesn't store the bytes into cache file ( it doesn't not store file into phone)
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[[NSURL alloc] initWithString:#"http://testing.io/dev.php/video/verifyReceipt"]];
[request setPostValue:resultAsString forKey:#"verify"];// sending json in post
[request setDidReceiveDataSelector:#selector(request:didReceiveBytes:)];
[request setDidFinishSelector:#selector(requestDone:)];
[request setTimeOutSeconds:120];
[request setDelegate:self];
[request setNumberOfTimesToRetryOnTimeout:2];
[request setDownloadProgressDelegate:self];
request.showAccurateProgress = YES;
[request startSynchronous];
}
-(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
{
[videoData appendData:data];// appending data with global NSmutabledata
NSLog(#"data is %#",data);
}
- (void)requestDone:(ASIHTTPRequest *)request{
//[MBProgressHUD hideHUDForView:self.view animated:YES];
// SAVED Video PATH
// Get the Document directory
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// Add your filename to the directory to create your saved video location
NSString* movLocation = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
if(request.responseStatusCode==200)
{
[videoData writeToFile:movLocation atomically:NO];
NSLog(#"in request done sucsessfully downlaod and store in database %d",request.responseStatusCode);
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
else{
NSLog(#"in request downlaod and store in database failed %#",request.responseHeaders);
}
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(#"%#",request.error);
}
fileUrl = string of URL to download a video.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[fileUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:destPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
// Give alert that downloading successful.
NSLog(#"Successfully downloaded file to %#", destPath);
/* To call delegate to response the result. */
[self.target parserDidDownloadItem:destPath];
HUD.detailsLabelText = [NSString stringWithFormat:#"%# %i%%",[JGlobals getLocalvalue:#"Downloading"],100];
[HUD hide:TRUE];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Give alert that downloading failed
NSLog(#"Error: %#", error);
/* To call delegate to response the result. */
[self.target parserDidFailToDownloadItem:error];
[HUD hide:TRUE];
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
{
// Progress
float totalProgress = (totalBytesWritten / (totalBytesExpectedToWrite * 1.0f) * 100);
HUD.detailsLabelText = [NSString stringWithFormat:#"Downloading %i%%", MIN((int)(totalProgress), 99)];
}];
[operation start];
I'm thinking of a method which might not be the right one, but it going to save you from writing a lot of code.
First set a normal UIProgressView instance as the download progress delegate like this
[request setDownloadProgressDelegate:uiprogreeViewInstance];
Now ASIHTTPRequest framework will take care of updating that progressview when the downloading will be taking place. ProgressView has a property named progress, which ranges from 0.0 to 1.0.
Now instantiate MBProgressHUD, add it as your subview where you want. Set the progress value of the MBProgressHUD instance to that of the UIProgressView. Hide the uiprogressview instance.

iPhone/Objective-C: How to modify UILabel from timer

I have the following timer:
uploadGPS_timer=[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(uploadGPS_tick:) userInfo:nil repeats:YES];
[self uploadGPS_tick:nil];
And here is the callback: uploadGPS_tick():
-(void)uploadGPS_tick:(NSTimer*)timer{
if(!lat || !lng){
//do nothing
}else{
NSString *urlStr=[[NSString alloc] initWithFormat:#"http://www.example.com/ajax/updateCoords.php"];
NSURL *url=[NSURL URLWithString:urlStr];
__block ASIFormDataRequest *request=[[ASIFormDataRequest alloc ]initWithURL:url];
[request setPostValue:lat forKey:#"lat"];
[request setPostValue:lng forKey:#"lng"];
NSLog(#"EOH: %#",lat);
[request setDelegate:self];
[request setCompletionBlock:^{
NSString *response=[request responseString];
NSLog(#"%#",response);
if([response isEqualToString:#"LO"]){
[self.navigationItem setBackBarButtonItem:nil];
DriverLogin *x= [[DriverLogin alloc] initWithNibName:nil bundle:nil];
[[self navigationController]pushViewController:x animated:NO];
}
SBJsonParser *parser=[[SBJsonParser alloc]init];
NSMutableDictionary *obj=[[NSMutableDictionary alloc]init ];
obj=[[parser objectWithString:[request responseString] error:nil]retain];
credits.text=[[obj objectForKey:#"credits"] stringValue]; //this won't show...
creditsUsed.text=[[obj objectForKey:#"creditsUsed"] stringValue]; //this won't show...
NSInteger timeLeftSecs=[[obj objectForKey:#"creditTimeLeft"] intValue];
NSInteger timeLeftMins=(int)(timeLeftSecs/60);
creditTimeLeft.text=[[NSString alloc]initWithFormat:#"%d",timeLeftMins]; //this won't show...
NSLog(#"xxx:%#",obj);
}];
[request setFailedBlock:^{
NSError *error =[request error];
NSLog(#"%#",error);
//do nothing
}];
[request startAsynchronous];
}
}
As you can see, every five seconds, a JSON object is sent from the server. This JSON object is then parsed and three UILabels are set based on this JSON data.
The trouble I'm having is that the UILabels aren't getting their text set! Even though I can clearly see NSLog(#"xxx:%#",obj); in the debugger. The UILabels are connected properly in the .xib.
Any help greatly appreciated.
You should do it from main thread. Replace the label text assignment with following code:
dispatch_async(dispatch_get_main_queue(), ^{
creditTimeLeft.text=[NSString stringWithFormat:#"%d",timeLeftMins];
});

app is crashing due to tiny_malloc_from_free_list

Am working on an iPhone app,everything was going fine until I faced this crash, tiny_malloc_from_free_list. I am not sure why this crash is happening all of a sudden.Tried to google it but seems there aint enough suggestions to fix this one.
Please suggest any ideas how I can fix this problem.
Thanks,
Manoj
for reference here are some methods:
-(void) fetchProfileData
{
// Implemented ASIHTTP Request APIs
NSURL *url = [[NSURL URLWithString:SERVICE_NAME_PROFILEMANAGER] autorelease];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setValidatesSecureCertificate:NO];
[request setUsername:[[LoginManager sharedInstance] userName]];
[request setPassword:[[LoginManager sharedInstance] passWord]];
[request setDelegate:self];
[self.view addSubview:autheticateIndicator];
[autheticateIndicator startAnimating];
[authenticationLabel setHidden:NO];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
NSString *theXml = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
[NSThread detachNewThreadSelector:#selector(parseXML:) toTarget:self withObject:theXml];
[autheticateIndicator stopAnimating];
[theXml release];
}
-(void) parseXML:(NSString *)xmlData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[profilePersonnelNumber removeAllObjects];
// Load and parse the string data
tbxml = [[TBXML tbxmlWithXMLString:xmlData] retain];
// If TBXML found a root node, process element and iterate all children
if (tbxml.rootXMLElement) {
[self traverseElement:tbxml.rootXMLElement];
}
if ([profilePersonnelNumber count] > 0 ) {
NSDictionary *dict = [profilePersonnelNumber objectAtIndex:0];
if ([dict objectForKey:#"PersonnelNumber"])
{
[array release];
array = [[NSMutableArray arrayWithObjects:[dict valueForKey:#"PersonnelNumber"], nil] retain];
NSMutableString * result = [[NSMutableString alloc] init];
for (NSObject * obj in array)
{
[result appendString:[obj description]];
[[LoginManager sharedInstance] personnelNumber:[obj description]];
}
[result release];
}
}
[tbxml release];
[pool release];
//TODO: Uncomment this part, must required
if ([profilePersonnelNumber count] > 0) {
UITabBarController *controller = self.tabBarController;
[self presentModalViewController:controller animated:YES];
}
}

Synchonous SSL certificate handling on iPhone

I was wondering if anyone can help me understand how to add SSL certificate handling to synchronous
connections to a https service.
I know how to do this with asynchronous connections but not synchronous.
NSString *URLpath = #"https://mydomain.com/";
NSURL *myURL = [[NSURL alloc] initWithString:URLpath];
NSMutableURLRequest *myURLRequest = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[myURL release];
[myURLRequest setHTTPMethod:#"POST"];
NSString *httpBodystr = #"setting1=1";
[myURLRequest setHTTPBody:[httpBodystr dataUsingEncoding:NSUTF8StringEncoding]];
NSHTTPURLResponse* myURLResponse;
NSError* myError;
NSData* myDataResult = [NSURLConnection sendSynchronousRequest:myURLRequest returningResponse:&myURLResponse error:&myError];
//I guess I am meant to put some SSL handling code here
Thank you.
Using the static sendSynchronousRequest function is not posible, but i found an alternative.
First of all NSURLConnectionDataDelegate object like this one
FailCertificateDelegate.h
#interface FailCertificateDelegate : NSObject <NSURLConnectionDataDelegate>
#property(atomic,retain)NSCondition *downloaded;
#property(nonatomic,retain)NSData *dataDownloaded;
-(NSData *)getData;
#end
FailCertificateDelegate.m
#import "FailCertificateDelegate.h"
#implementation FailCertificateDelegate
#synthesize dataDownloaded,downloaded;
-(id)init{
self = [super init];
if (self){
dataDownloaded=nil;
downloaded=[[NSCondition alloc] init];
}
return self;
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace {
NSLog(#"canAuthenticateAgainstProtectionSpace:");
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge {
NSLog(#"didReceiveAuthenticationChallenge:");
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[downloaded signal];
[downloaded unlock];
self.hasFinnishLoading = YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[dataDownloaded appendData:data];
[downloaded lock];
}
-(NSData *)getData{
if (!self.hasFinnishLoading){
[downloaded lock];
[downloaded wait];
[downloaded unlock];
}
return dataDownloaded;
}
#end
And for use it
FailCertificateDelegate *fcd=[[FailCertificateDelegate alloc] init];
NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO];
[c setDelegateQueue:[[NSOperationQueue alloc] init]];
[c start];
NSData *d=[fcd getData];
Now you will have all benefits of have an async use of nsurlconnection and benefits of a simple sync connection, the thread will be blocked until you download all data on the delegate, but you could improve it adding some error control on FailCertificateDelegate class
EDIT: fix for big data. based on Nikolay DS comment. Thanks a lot
I had a similar issue. In my case i had an a-synchronous connection working with ssl as required using the two delegate methods that allowed me to accept any certificate:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
But i was stuck on doing the same in a synchronous manner. I searched the web until i found your post and unfortunately another stackoverflow post where it is hinted that you cannot perform synch calls on NSURLConnection and work with ssl (because of the lack of a delegate to handle the ssl authentication process).
What i ended up doing is getting ASIHTTPRequest and using that. It was painless to do and took me about an hour to set up and its working perfectly. here is how i use it.
+ (NSString *) getSynchronously:(NSDictionary *)parameters {
NSURL *url = [NSURL URLWithString:#"https://localhost:8443/MyApp/";
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSString *parameterJSONString = [parameters JSONRepresentation];
[request appendPostString:parameterJSONString];
[request addRequestHeader:#"User-Agent" value:#"MyAgent"];
request.timeOutSeconds = CONNECTION_TIME_OUT_INTERVAL;
[request setValidatesSecureCertificate:NO];
[request startSynchronous];
NSString *responseString = [request responseString];
if (request.error) {
NSLog(#"Server connection failed: %#", [request.error localizedDescription]);
} else {
NSLog(#"Server response: %#", responseString);
}
return responseString;
}
The important part of course is the
[request setValidatesSecureCertificate:NO];
Another alternative for you is to handle the download in another thread with an a-synch connection using the two methods above and block the thread from which you want the synch connection until the request is complete
Im close to finding the solution for this with the code below. This works but often crashes
probably because I am doing something wrong in the way I code this and I don't have a strong understanding of the methods used. But if anyone has any suggestions on how to improve this
than please post.
Just after the line:
NSError* myError;
and just before the line:
NSData* myDataResult = [NSURLConnection sendSynchronousRequest:myURLRequest
returningResponse:&myURLResponse error:&myError];
add:
int failureCount = 0;
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost:#"mydomain.com" port:443 protocol:#"https" realm:nil
authenticationMethod:NSURLAuthenticationMethodServerTrust];
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:myURL MIMEType:#"text/html"
expectedContentLength:-1 textEncodingName:nil];
NSURLAuthenticationChallenge *challange = [[NSURLAuthenticationChallenge alloc]
initWithProtectionSpace:protectionSpace proposedCredential:[NSURLCredential
credentialForTrust:protectionSpace.serverTrust] previousFailureCount:failureCount
failureResponse:response error:myError sender:nil];