AFNetworking failure block - ios

i'm using afnetworking 2.0 to show youtube videos.
When i have a connection error, i open an alert view and i'd like stop the request if i click "ok".
Alert view is showed correctly but when i click "ok" the request isn't stopped and i see activity indicator.
How can i stop the request?
This is the code below:
-(void)loadData {
NSString *urlAsString = #"https://gdata.youtube.com/feeds/api/videos?q=wankel&v=2&max-results=50&alt=jsonc";
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] init];
activityIndicator.color = [UIColor blackColor];
activityIndicator.backgroundColor = [UIColor blackColor];
[activityIndicator startAnimating];
[self.view addSubview:activityIndicator];
activityIndicator.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2 );
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
self.moviesArray = [responseObject valueForKeyPath:#"data.items"];
NSLog(#"%#", moviesArray);
self.thumbnailsArray = [responseObject valueForKeyPath:#"data.items.thumbnail"];
self.moviesDetailArray = [responseObject valueForKeyPath:#"data.items"];
[activityIndicator setHidden:YES];
[activityIndicator stopAnimating];
[self.collectionView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
UIAlertView *alertView =[[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat:#"%#", error.localizedDescription] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Try again", nil];
[activityIndicator setHidden:YES];
[activityIndicator stopAnimating];
[alertView show];
}];
[operation start];
}

Have you tried adding the operation to a AFHTTPRequestOperationManager ?
The manager has an operationQueue property. You can cancel operations from there.
When the operation fails, stop the operation from the shared manager.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.operationQueue cancelAllOperations];
Edit:
If you're looking for a specific operation you can iterate through the operations in the queue:
for (NSOperation *operation in manager.operationQueue.operations) {
// check if this is the right operation, and cancel it.
}

try putting
[operation cancel];
in your failure block

Related

Collection View freezes for long when populated using response obtained by hitting API

I am trying to get data from server and populate collection view cells with that data, but when collection view gets populated freezes and takes very long time to scroll.
What is exactly going wrong?
-(void)callService:(NSNumber*)categoryid{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFJSONResponseSerializer
serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
NSMutableDictionary *dict = [NSMutableDictionary new];
[dict setValue:#1 forKey:#"page"];
[dict setValue:#25 forKey:#"limit"];
[dict setValue:categoryid forKey:#"category_id"];
[manager POST:#"https://www.foodfuels.com/Api/getrecipes"
parameters:dict progress:nil success:^(NSURLSessionTask *task,id responseObject)
{
int status = [[responseObject objectForKey:#"status"] intValue];
if(status == 200)
{
responseArray = [responseObject valueForKey:#"data"];
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:true];
[_outerCollectionView reloadData];
});
}
else
{
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"logininfo"];
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Error" message:#"some eror!" delegate:self cancelButtonTitle:Nil otherButtonTitles:#"Ok", nil];
[alert show];
}
dispatch_async(dispatch_get_main_queue(), ^{
//[MBProgressHUD hideHUDForView:self.view animated:YES];
});
}
failure:^(NSURLSessionTask *operation, NSError *error)
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Error" message:error.localizedDescription delegate:self cancelButtonTitle:Nil otherButtonTitles:#"Ok", nil];
[alert show];
dispatch_async(dispatch_get_main_queue(), ^{
// [MBProgressHUD hideHUDForView:self.view animated:YES];
});
}];
}
Collection View
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
if(collectionView==_headingCollectionView){
recipeHeading = (RecipeHeadingCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"headingCell" forIndexPath:indexPath];
_headingCollectionView.delegate = self;
[recipeHeading.headingBtn setTitle:[recipeTypeArray objectAtIndex:indexPath.row] forState:UIControlStateNormal];
[recipeHeading.headingBtn addTarget:self action:#selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];
bool d = [allValues[indexPath.row] boolValue];
if(d)
{
[recipeHeading.headingBtn setTitleColor:[UIColor colorWithRed:36/255.0 green:71/255.0 blue:113/255.0 alpha:1.0] forState:UIControlStateNormal]; [recipeHeading.headingBtn addSubview:bottomBorder];
}
else
{
[recipeHeading.headingBtn setTitleColor:[UIColor whiteColor]forState:UIControlStateNormal];
}
return recipeHeading;
}
else if (collectionView==_outerCollectionView){
RecipeOuterCell *outerCell =(RecipeOuterCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"outerCell" forIndexPath:indexPath];
return outerCell;
}
else{
RecipeInnerCell *innerCell = (RecipeInnerCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"innerCell" forIndexPath:indexPath];
[innerCell populateRecipeScreen:responseArray index:indexPath];
return innerCell;
}
}
Inner Collection View Cell
-(void)populateRecipeScreen:(NSArray*)recipeResponseArr index:(NSIndexPath*)path{
NSLog(#"the value of recipe array are as follows %#",recipeResponseArr);
for(int i=0;i<recipeResponseArr.count;i++){
self.comment_Count.text =[[[recipeResponseArr valueForKey:#"comment_count"]objectAtIndex:path.row]stringValue];
self.titleLbl.text =[[recipeResponseArr valueForKey:#"description"]objectAtIndex:path.row];
self.like_Count.text = [[[recipeResponseArr valueForKey:#"like_count"]objectAtIndex:path.row]stringValue];
NSData *data= [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: [[[recipeResponseArr valueForKey:#"user"]valueForKey:#"image"] objectAtIndex:path.row]]];
; self.smallImgView.image=[UIImage imageWithData:data];
self.share_Count.text = [[[recipeResponseArr valueForKey:#"share_count"]objectAtIndex:path.row]stringValue];
self.subTitleLbl.text = [[[recipeResponseArr valueForKey:#"user"]valueForKey:#"username"] objectAtIndex:path.row];
NSLog(#"url obtained as result %#",[[[recipeResponseArr valueForKey:#"upload_images"]valueForKey:#"name"] objectAtIndex:path.row]);
NSArray *urlString = [[[recipeResponseArr valueForKey:#"upload_images"]valueForKey:#"name"] objectAtIndex:path.row];
NSData *mainData=[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[urlString objectAtIndex:0]]];
self.mainImg.image=[UIImage imageWithData:mainData];
}
}
It seems like you are loading images from network (namely from recipeResponseArr["user"]["image"] in main thread via initWithContentsOfURL:. This is strongly discouraged and against best practised. From the documentation:
Important
Don't use this synchronous method to request network-based URLs. For
network-based URLs, this method can block the current thread for tens
of seconds on a slow network, resulting in a poor user experience, and
in iOS, may cause your app to be terminated.
Instead, for non-file URLs, consider using the
dataTaskWithURL:completionHandler: method of the NSURLSession class.
See URL Session Programming Guide for details.
If you need effective and easy tool to load images I would recommend using SDWebImage or AlamofireImage

GCD in iOS not updating my label

I am trying to update my custom label using GCD however all I am getting is the text I initialized the label with:
-(void)drawCardInfo{
__block NSString *cardString;
PPLinearLayoutLabelItem *cardDetails = [[PPLinearLayoutLabelItem alloc] initWithText:#"CREDIT CARD INFO" font:[PPFonts regular18] maxWidth:[LayoutValues getMaxWidthClipped]];
[cardDetails setPaddingTop:20];
[cardDetails setPaddingBottom:10];
[self.topContainerContent addObject:cardDetails];
PPLinearLayoutLabelItem *cardInfo = [[PPLinearLayoutLabelItem alloc] initWithText:#"Data" font:[PPFonts bold16] maxWidth:[LayoutValues getMaxWidthClipped]];
[cardInfo setPaddingTop:0];
[self.topContainerContent addObject:cardInfo];
LinearLayoutHorizontalLine *line1 = [[LinearLayoutHorizontalLine alloc] initWithMaxWidth:[LayoutValues getMaxWidthClipped]];
[self.topContainerContent addObject:line1];
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init];
networkQueue.maxConcurrentOperationCount = 5;
NSURL *url = [NSURL URLWithString:#"https://xxxxxxxxxxxxxxxxxx"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
if([string isEqualToString:#""]){
} else {
NSMutableDictionary *dict=[NSJSONSerialization JSONObjectWithData:[string dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
NSString *cardType = [dict objectForKey:#"credit_card_type"];
NSString *cardFinalFour = [dict objectForKey:#"credit_card_last_4"];
cardString = [NSString stringWithFormat:#"%# **** %#",cardType, cardFinalFour];
NSLog(#"%#",cardString);
}
dispatch_async(dispatch_get_main_queue(), ^{ [cardInfo setText:cardString]; });
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%s: AFHTTPRequestOperation error: %#", __FUNCTION__, error);
}];
[networkQueue addOperation:operation];
});
}
I am successfully logging out the value proving that the network call works fine on a separate thread. Still my label is not being updated. How can I mitigate this?
Looks like you are trying to update the text for the label in a background thread. Updating UI elements on anywhere other than the main thread is not such a good idea since you never know when a asynchronous job will finish.
You can use the following ways to go about it:
Get the main thread and then update the text label
dispatch_async(dispatch_get_main_queue(), ^{
//Code here to which needs to update the UI in the UI thread goes here
});
Use dispatch_sync
Use NSOperations with dependancies (This will be the longest)

AFNetworking fail with response.statusCode 0

I want to get address from latitude and longitude with GoogleGEO CODING (EX URL = http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true_or_false )
So I want to get JSON from that page by AFNetworking.
It's my code below :
IBAction)reLocation:(UIButton*)sender
{
if(sender.tag==1)
{
NSArray *gpsValue = [self getGPS];
float lat = [[gpsValue objectAtIndex:0] floatValue];
float lon = [[gpsValue objectAtIndex:1] floatValue];
NSString *string = [NSString stringWithFormat:#"%#%#,%#&sensor=true_or_false",GEOCODING_URL,[NSString stringWithFormat:#"%f", lat],[NSString stringWithFormat:#"%f",lon]]; // NSString *str = [NSString stringWithFormat:#"%f", myFloat];
NSLog(string);
NSURL *url = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"AFNetworking success");
NSDictionary *location = (NSDictionary *)responseObject;
// 3
self.title = #"JSON Retrieved";
//[self.tableView reloadData];
NSLog(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"AFNetworking failure");
switch (operation.response.statusCode) {
case 400:
// Do stuff
NSLog(#"error 400");
break;
default:
NSLog([NSString stringWithFormat:#"%ld",(long)operation.response.statusCode]);
break;
}
// 4
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}];
// 5
[operation start];
}}
But when I click my button, always afnetworking fails and log shows 0 for status code.
I also got url log that i put in
i already checked that url is not problem (it shows json in working order)
I debug with simulator!
Is there something I miss ?

How to calculate progress of MBProgressHUD mode when used with NSURLConnection?

I am trying to use MBProgressHUD with NSURLConnection, but I'm not sure how to make the animation spin in MBProgressHUDModeDeterminate.
Basically I have this code in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
[self fetchFromServer];
self.HUD = [ [MBProgressHUD alloc] initWithView:self.view];
self.HUD.labelText = #"Loading Schedule...";
[self.view addSubview:self.HUD];
self.HUD.dimBackground = YES;
[self.HUD show:YES];
}
When this view is loaded, I call a method to fetch from the database. I want MBProgressHUD to load. Then I want it to end once the data has been fetched.
- (void)fetchFromServer
{
NSURL *url = [[NSURL alloc] initWithString:#"url.com"];
[NSURLConnection sendAsynchronousRequest:[ [NSURLRequest alloc] initWithURL:url] queue:[ [NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray *jsonObj = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:&error];
scheduleJSONArray = jsonObj;
// Progress in HUD should end here after scheduleJSONArray is set
[self.HUD hide:YES];
} ];
}
I don't know what to use to update the progress of HUD. Can anyone assist?
Thanks
You better use AFNetworking:
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
// Set up HUD
__weak ViewController *weakSelf = self;
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:#"url.com" parameters:nil error:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__weak AFHTTPRequestOperation *weakOperation = operation;
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
[weakSelf updateHUDForOpetation:weakOperation
totalBytes:totalBytesExpectedToRead
readBytes:totalBytesRead
index:[videoNames indexOfObject:videoName]
total:videoNames.count];
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
}];
Then update HUD manually. Like this:
- (void)updateHUDTotalBytes:(long long)totalBytes
readBytes:(long long)readBytes {
MBProgressHUD *HUD = [MBProgressHUD HUDForView:self.view];
HUD.mode = MBProgressHUDModeDeterminate;
HUD.labelText = [NSString stringWithFormat:#"%lld/%lld", readBytes / 1024, totalBytes / 1024];
HUD.progress = (double)readBytes / (double)totalBytes;
}

Update UI on main thread from AFHTTPRequestOperation

I've built a Rails backend for an iOS app that lets users access a RESTful API only after having authorized the device. Basically authorization is managed by retrieving a token.
When the user submits username and password, the webservice gets called with an AFHTTPRequestOperation (see code below). I also display to the user a HUD (MBProgressHUD) to track the progress of the request. I've set up callbacks for success and failure and I want to update the HUD and let it stick onscreen with an updated message for a couple of seconds before dismissing it.
//Set HUD
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = #"Authenticating";
//Set HTTP Client and request
NSURL *url = [NSURL URLWithString:#"http://localhost:3000"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient setParameterEncoding:AFFormURLParameterEncoding]; //setting x-www-form-urlencoded
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"/api/v1/tokens.json" parameters:#{#"password":_passwordField.text, #"email":_emailField.text}];
//Set operation
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
//Success and failure blocks
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
NSError *error;
NSDictionary* jsonFromData = (NSDictionary*)[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:&error];
NSLog(#"%#", jsonFromData);
_statusLabel.text = #"Device authenticated!";
hud.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
hud.mode = MBProgressHUDModeCustomView;
hud.labelText = #"Authenticated!";
sleep(2);
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(#"Error");
sleep(2);
_statusLabel.text = #"Wrong username or password!";
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
}];
When the success / failure operation callbacks get called:
I try to update the HUD mode and text;
I wait sleep() for a couple of seconds;
I dismiss the HUD [MBProgressHUD hideAllHUDsForView:self.view animated:YES];;
I've also tried using dispatch_queue_t dispatch_get_main_queue(void); and run the HUD update on the main thread but to no avail.
Any ideas on what am I getting wrong?

Resources