Passing an object into a ASIHTTPRequest block - ios

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];
}

Related

cancel NSURLConnection in ios

I am calling webservice on mapView drag/regionChange. I want to keep some delay in the web service calls. So I want that whenever the user drags the map multiple times, all previous web service calls should be cancelled and only last drag web service call should be fired.
How do I do this?
Following is my code:
{ .... NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[data length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:data];
[request setHTTPMethod:#"POST"];
NSMutableDictionary __block *dictResponse;
[[NSOperationQueue mainQueue] cancelAllOperations];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if(connectionError == nil){
dictResponse = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&connectionError];
}
You cannot cancel a sendAsynchronousRequest. If you used a delegate-based NSURLConnection request, then you could cancel it, but (a) that's more coding than you probably want to bother with; (b) NSURLConnection is deprecated, so you should be NSURLSession anyway; and (c) NSURLSession allows you to cancel the task using the NSURLSessionTask reference that is returned to you:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPBody:data];
[request setHTTPMethod:#"POST"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"connection error = %#", error);
return;
}
NSError *parseError;
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&parseError];
if (!responseObject) {
NSLog(#"parse error = %#", parseError);
}
dispatch_async(dispatch_get_main_queue(), ^{
// use response here; e.g., updating UI or model objects
});
}];
[task resume];
If you need to cancel this request, just call [task cancel]. So save this NSURLSessionTask in some weak variable if you want to keep track of it and cancel it later.
Don't use the sendAsynchronousRequest convenience API, use the main delegate API so you have access to the instance of NSURLConnecyion to call cancel on.
Also, don't cancel operations on the main queue, you don't know what's there, and consider using NSURLSession

Calling NSURLConnection one by one

I have a NSMutableArray containing 10 URLs from which I need to grab the HTTP headers.
Below is my code:
for(int i=0; i<[contactsArray count];i++)
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSString *reqstr=[NSString stringWithFormat:#"%#",urlString ];
[request setURL:[NSURL URLWithString:reqstr]];
NSLog(#"requested url is %#",reqstr);
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:[mDict JSONData]];
NSURLConnection *theConnection=[[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
}
current result: all requests are going to server at a time.
expected result: want to send one request to sever after getting response I want to send another request in background.
Any suggestions?
Refactor your code to use the sendAsynchronousRequest:queue:completionHandler: method, and call itself once the current post is complete:
Move your count to an instance variable. Let's call it currentItem. Your code might look something like this:
- (void) postItems;
{
while (currentItem < [contactsArray count)
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSString *reqstr=[NSString stringWithFormat:#"%#",urlString ];
[request setURL:[NSURL URLWithString:reqstr]];
NSLog(#"requested url is %#",reqstr);
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:[mDict JSONData]];
[NSURLConnection sendAsynchronousRequest: request
queue: dispatch_get_main_queue ()
completionHandler: ^(NSURLResponse *response, NSData *data, NSError *error)
{
//check for errors
//save any response data
//Now trigger the next request
currentItem++
[self postItems];
}
];
}
}
(The syntax for the completion block might not be exactly right. I struggle a little with the syntax for blocks that take parameters.)
You use ASIHTTPRequest asynchronous call:
Link for ASIHTTPRequest
Then write like following code:
for(int i=0; i<[contactsArray count];i++)
{
NSURL* url = [NSURL URLWithString:urlString];
__block ASIHTTPRequest* request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^
{
//NEED SOMEHOW RETURN TRUE IF SUCESSED
}];
[request setFailedBlock:^
{
//NEED RETURN FALSE
}];
[request startAsynchronous];
}

Though I follow _Block , Memory Leak Happening # ASIHTTPRequest

Its my code , can you help where am I missing to handle Memory? I'm using X-Code 4.6. And also I have checked instrument , to get other memory leaks. Its almost showing all "ASIHTTPRequest". Im not handling manually like [request release]; Is that necessary to fix memory leak? Thanks in advance
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
}];
[request setFailedBlock:^{
}];
[request setTimeOutSeconds:60];
[request startAsynchronous];
It leaks because of the retain cycle created between the block and the request object.
Try the below:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
__weak ASIHTTPRequest *weakRequest = request;
[request setCompletionBlock:^{
}];
[request setFailedBlock:^{
}];
[request setTimeOutSeconds:60];
[request startAsynchronous];
Cheers..
EDIT:
ASIHTTPRequest is not supported anymore, try to move to AFNetworking, it is the best.
Then instead do this:
__weak __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
__strong ASIHTTPRequest *requestInBlock = request;
//your code, and replace all refrences of request inside the block with requestInBlock.
}];
[request setFailedBlock:^{
//same here
}];
[request setTimeOutSeconds:60];
[request startAsynchronous];
try this out.

ASIHTTPRequest delegation

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.

ASIHTTPRequest cansel request (using block)

I need to cancel my request. How can I make this. I have tried to create property and use it as assign for ASIHTTPRequest *request. But when I called [request cancel] I have bed access, because request retain count has 0 (due [ASIHTTPRequest requestWithURL:url] return autorelease object). I can't create strong property, I get this warning:
Capturing 'request' strongly in this block is likely to lead to a retain cycle
This is my code below:
__unsafe_unretained __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
NSString *response = [request responseString];
}];
[request setFailedBlock:^{
}];
[request startAsynchronous];

Resources