Objective C, update table view after async operation - ios

I am running an async operation which loops through a json data file which should then update a table view.
Here's the code i'm using.
-(void) TopDealsRecieve:(NSString *)Devicetoken;
{
currentcount = 0;
allcontent = newArray;
//Send device token and retireve TopDeals
NSString *mainURL = #"http://myurl.com/api/";
NSString *firstprefix = #"type=apicall&device=";
NSString *deviceIDforURL = [NSString stringWithFormat:#"%#", Devicetoken];
NSString *stringToGoToEncoder = [NSString stringWithFormat: #"%#%#", firstprefix, deviceIDforURL];
NSData *plainData = [stringToGoToEncoder dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64String = [plainData base64EncodedStringWithOptions:0];
NSString *returnURL = [NSString stringWithFormat:#"%#%#", mainURL, base64String];
NSURL *returncompletedURL = [[NSURL alloc] initWithString:returnURL];
//Retrieve Dictionary of Top Deals
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:returncompletedURL];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//Get all output and store for segue
NSLog(#"%#", responseObject);
currentcount++;
numrows = [responseObject valueForKey:#"rows"];
numrowscompare = [numrows integerValue];
allLogos = [[responseObject valueForKey:#"data"] valueForKey:#"logo"];
allcontent = [[responseObject valueForKey:#"data"] valueForKey:#"content"];
allpostode = [[responseObject valueForKey:#"data"] valueForKey:#"postcode"];
NSLog(#"%lu", (unsigned long)allcontent.count);
allname = [[responseObject valueForKey:#"data"] valueForKey:#"name"];
alladdress = [[responseObject valueForKey:#"data"] valueForKey:#"address"];
alladdress2 = [[responseObject valueForKey:#"data"] valueForKey:#"address2"];
alllat = [[responseObject valueForKey:#"data"] valueForKey:#"lat"];
alllong = [[responseObject valueForKey:#"data"] valueForKey:#"lng"];
allstart = [[responseObject valueForKey:#"data"] valueForKey:#"start"];
allfinish = [[responseObject valueForKey:#"data"] valueForKey:#"finish"];
allstartnice = [[responseObject valueForKey:#"data"] valueForKey:#"nicestart"];
allfinishnice = [[responseObject valueForKey:#"data"] valueForKey:#"nicefinish"];
// hide the ticker
[self.tableview reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// 4
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Top Deals check internet connection!"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}];
[operation start];
}
When running the operation all the data comes in fine to the console, however the table view does not update with the correct data. It updates with the data in the all content array from before calling the function.
It seems that the data from the server isn't being passed to the table view quick enough. I somehow need to get the table view to reloadData AFTER the operation has been completed in some sort of queue.
[self.tableview reloadData];
Sorry if not too clear, any help appreciated.

If allContent is the NSArray your UITableViewDatasource uses, then you never update it in your completionBlockWithSuccess, so this isn't a problem of async update but rather a simple mistake : update allContent just before calling reloadData.
(One additionnal remark : using 'Global' arrays is bad!)

Related

Objective C setting labels after api call

UPDATE
I am making an api call getPacks() and successfully getting the values of two variables _numberOfPacks and _numberOfAutoRefills.
However, when I try to put it in a label it fails and gives output as (null) Packs & (null) Autorefiils
the calls are made in the following order:
getpacks()-------first (it sets value on _numberOfPacks and _numberOfAutoRefills as global variables
drawQuantity()-----set _numberOfPacks and _numberOfAutoRefills on labels.
-(void) getPacks: (IHPlacedOrder*)order{
NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init];
networkQueue.maxConcurrentOperationCount = 5;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://XXXXXXX.XXXXX/%#",order.ID]];
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];
NSLog(#"%#",dict);
_numberOfPacks = [[dict objectForKey:#"prescription_interval"] valueForKey:#"quantity_per_interval"];
_numberOfAutoRefills = [[dict objectForKey:#"prescription_interval"]valueForKey:#"num_intervals"];
NSLog(#"PACKS:%# , AUTOREFILLS:%#",_numberOfPacks,_numberOfAutoRefills);
_quantity.text = [NSString stringWithFormat: #"%#,%#",_numberOfPacks,_numberOfAutoRefills];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%s: AFHTTPRequestOperation error: %#", __FUNCTION__, error);
}];
[networkQueue addOperation:operation];
}
followed by:
-(void)drawQuantity: (IHPlacedOrder*)order{
PPLinearLayoutLabelItem *quantityLabel = [[PPLinearLayoutLabelItem alloc] initWithText:[NSString stringWithFormat:#"%# QUANTITY & %# REFILLS", _numberOfPacks,_numberOfAutoRefills] font:[PPFonts regular18] maxWidth:[LayoutValues getMaxWidthClipped]];
[quantityLabel setPaddingBottom:5];
[quantityLabel setPaddingTop:20];
[self.topContainerContent addObject:quantityLabel];
NSString* quantityText = [NSString stringWithFormat:#"Packs + Autorefills"];
PPLinearLayoutLabelItem *quantity = [[PPLinearLayoutLabelItem alloc] initWithText:quantityText font:[PPFonts genericParagraphFontBold] maxWidth:[LayoutValues getMaxWidthClipped]];
[quantity setPaddingBottom:20];
[self.topContainerContent addObject:quantity];
LinearLayoutHorizontalLine *line1 = [[LinearLayoutHorizontalLine alloc] initWithMaxWidth:[LayoutValues getMaxWidthClipped]];
[self.topContainerContent addObject:line1];
}
I found the solution. I was using wrong method call to set labels. The thing is my application uses PPLinearLayoutLabelItem as a custom built label. I had to call [self.quantity setLabel:#"%#",data_fromapi] to make it work. setText would just set the text within PPLinearLayoutLabelItem class and not set the Label.

Upload 5 images to server using AFNetworking [duplicate]

This question already has answers here:
AFNetworking multiple files upload
(3 answers)
Closed 6 years ago.
I used Afnetworking in my app,I need to post 5 images to server, 5 images as array, this array was one of my **request parameters.
this is correct way or wrong one, there is any one more performance than it ? -
(IBAction)sPActionButton:(id)sender {
NSUserDefaults *def=[NSUserDefaults standardUserDefaults];
NSString * language=[def objectForKey:#"Language"];
NSString * deviceToken=[def objectForKey:#"dT"];
[par setObject:deviceToken forKey:#"dT"];
NSString *check=[def objectForKey:#"Log"];
[par setObject:check forKey:#"aT"];
//---------------------------------------------
NSString * apiKey=APIKEY;
[par setObject:apiKey forKey:#"aK"];
[par setObject:language forKey:#"lG"];
NSMutableArray *images = [NSMutableArray arrayWithCapacity:10];
for (int x=0; x<_chosenImages.count; x++) {
NSData *imageData = UIImageJPEGRepresentation(_chosenImages[x], 0.5);
NSLog(#"%#",imageData);
NSString *str=[Base64 encode:imageData];
[images addObject:str];
}
NSLog(#"%#",images);
[par setObject:images forKey:#"image[array]"];
if ([self validateAllFields]) {
NSLog(#"par = %#",par);
//-----------------------------------------------
[MBProgressHUD showHUDAddedTo:self.view animated:NO];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#/sellPrp?",BASEURl] parameters:par
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"JSON: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Data"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
[MBProgressHUD hideHUDForView:self.view animated:NO];
}];
}
}
- (void)prepareForImagePosting
{
if (imageCount < self.arrAllPostImages.count)//arrAllPostImages array contains images for posting and imageCount acts as iterator
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init]; //Prepare the dictionary which contains image for posting
[dict setObject:#"1" forKey:#"upload"];
[dict setObject:[[self.arrAllPostImages objectAtIndex:imageCount]objectForKey:#"SelectedPhoto"] forKey:#"post_image"];
[self postImage:dict];
}
else
return;
}
- (void)postImage: (NSMutableDictionary *)dictPostImages
{
NSError *error = nil;
NSString *url = POSTIMAGELINK;
NSMutableDictionary *postDict = [[NSMutableDictionary alloc]init];
[postDict setObject:[dictPostImages objectForKey:#"upload"] forKey:#"upload"];
NSData *jsonRequestDict = [NSJSONSerialization dataWithJSONObject:postDict options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonCommand = [[NSString alloc] initWithData:jsonRequestDict encoding:NSUTF8StringEncoding];
NSLog(#"***jsonCommand***%#",jsonCommand);
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:jsonCommand,#"requestParam", nil];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:url parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
if (isEnteredInFailureBlock == NO)
{
//here Image is posted
NSData *postPicData=UIImageJPEGRepresentation([dictPostImages objectForKey:#"post_image"], 0.5) ;
[formData appendPartWithFileData:postPicData
name:#"post_image"
fileName:[NSString stringWithFormat:#"image%d.jpg",imageCount]
mimeType:#"image/*"];
}
else
{
}
} success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSError *error = nil;
NSString *responseStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", responseStr);
NSMutableDictionary *jsonResponseDict = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
NSLog(#"Response Dictionary:: %#",jsonResponseDict);
if ([[jsonResponseDict objectForKey:#"status"] intValue] == 1)
{
if (isEnteredInFailureBlock == NO)
{
[self.arrSuccessfullyPostedImagesDetails addObject:jsonResponseDict];
if (appDel.successfullImgPostingCount == appDel.totalPostingImagesCount)
{
}
else
{
appDel.successfullImgPostingCount++;
imageCount++;
[self prepareForImagePosting];
}
}
else
{
self.arrSuccessfullyPostedImagesDetails = [[NSMutableArray alloc]init];
appDel.successfullImgPostingCount = 0;
appDel.totalPostingImagesCount = 0;
imageCount = 0;
return;
}
}
else
{
self.arrSuccessfullyPostedImagesDetails = [[NSMutableArray alloc]init];
appDel.successfullImgPostingCount = 0;
appDel.totalPostingImagesCount = 0;
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Request Error: %#", error);
isEnteredInFailureBlock = YES;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert!" message:#"Posting Unsuccessful" delegate:nil cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alert show];
// if image is not successfully posted then the server is informed with #"upload" #"0" so that the entire post is deleted from server
NSMutableDictionary *failureDict = [[NSMutableDictionary alloc]init];
[failureDict setObject:#"0" forKey:#"upload"];
[self postImage:failureDict];
}];
}

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 ?

Ui view freez for long time

I am working on afnetworking, i have web service that takes too much time to load data and i want that UI do not freeze, i used this tutorial to run webservice on background so that i can work on other views as well, but not sucess till yet.
-(void) getArticles :(NSString*)stateAbbre completionHandler:(void (^)(id array))success
{
[MyCommonFunctions showGlobalProgressHUDWithTitle:#"Loading"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *link = [NSString stringWithFormat:#"http://cloud.ilmasoft.com/depilex/depilexs/get_articles_ios.php"];
NSLog(#"%#",link);
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
[manager GET:link parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
NSDictionary *returnedDealDict = responseObject ;
NSArray *returnArray = [returnedDealDict objectForKey:#"Result"];
for(NSDictionary *dealDict in returnArray)
{
ArticlesDC *articles = [[ArticlesDC alloc] init];
articles.articlesID = [[dealDict objectForKey:#"id"]intValue ];
articles.articleTitle = [dealDict objectForKey:#"title" ];
articles.articleDetail = [dealDict objectForKey:#"details" ];
articles.articleDate = [dealDict objectForKey:#"date" ];
articles.articlePic = [dealDict objectForKey:#"pic" ];
articles.articleThumbPath = [dealDict objectForKey:#"thumb_path" ];
articles.articleStatus = [dealDict objectForKey:#"status" ];
[dataArray addObject:articles];
[MyCommonFunctions dismissGlobalHUD];
}
success(dataArray);
// [MBProgressHUD hideHUDForView:self.view animated:YES];
if (dataArray.count == 0)
{
ALERT_VIEW(#"Please check your internet connection.");
// [MBProgressHUD hideHUDForView:self.view animated:YES];
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
ALERT_VIEW(#"Error occured while loading data.");
// [MBProgressHUD hideHUDForView:self.view animated:YES];
}];
}
and in my view did load method
[self getArticles:nil completionHandler:^(id array) {
articlesArray = array;
[tblView reloadData];
for (ArticlesDC *article in articlesArray)
{
NSString *stringWithoutSpace = [[NSString stringWithFormat:#"http://cloud.ilmasoft.com/depilex/admin/%#", article.articleThumbPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString: stringWithoutSpace]];
UIImage *imgOne = [UIImage imageWithData:imageData];
NSString *stringforImg = [[NSString stringWithFormat:#"http://cloud.ilmasoft.com/depilex/admin/%#", article.articlePic] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *imageDta = [NSData dataWithContentsOfURL:[NSURL URLWithString: stringforImg]];
UIImage *imgTwo = [UIImage imageWithData:imageDta];
[dbHandler insertArticlesIntoSqlite:article.articleTitle andDetail:article.articleDetail anddate:article.articleDate andImage:[MyCommonFunctions saveImageInDocuments:imgTwo] andThumb:[MyCommonFunctions saveImageInDocuments:imgOne]];
[defaults setInteger:1 forKey:#"getArticlesOffline"];
[defaults synchronize];
}
}];
The problem is not AF, it's that at the end of that process you call dataWithContentsOfURL twice and this runs directly on the main thread to download some images. You need to move that download to a background thread.

block not being called on the other end

i'm new to blocks, I have a class of requests with static methods to call me back on UIViewControllers with some blocks
this is the method implementation :
(putting a breakpoint on the block(something) DOES stop there, like it should)
+(void)requestSuggestedLocationsForText:(NSString*)text withBlock:(void (^)(NSArray*callBackArray))block
{
if ([text isEqualToString:#""] || [text isEqualToString:#" "])
{
block(nil);
return;
}
NSString * key = #"someActualKeyHere";
;
NSString * finalText;
NSArray *tagschemes = [NSArray arrayWithObjects:NSLinguisticTagSchemeLanguage, nil];
NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options:0];
[tagger setString:text];
NSString *language = [tagger tagAtIndex:0 scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
if ([language isEqualToString:#"he"])
{
finalText = [text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
else
{
finalText = [text stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
}
NSString *urlString = [NSString stringWithFormat:
#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&types=geocode&sensor=true&key=%#",finalText,key];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (!responseObject && ![responseObject respondsToSelector:#selector(dataWithData:)])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving "
message:#"ERROR"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
return ;
}
NSData * responseData = [NSData dataWithData:responseObject];
NSString *responseString = [NSString stringWithUTF8String:[responseData bytes]];
NSError *err;
if ([responseString respondsToSelector:#selector(JSONObjectWithData:options:error:)])
{
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&err];
NSArray * predictions = [json valueForKey:#"predictions"];
block(predictions);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// 4
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}];
// 5
[operation start];
}
this is how I call it, notice the NSLog, i put a breakpoint on it and its never called
which is exactly what I want to occur.
[Requests requestSuggestedLocationsForText:text withBlock:^(NSArray *callBackArray)
{
NSLog(#"ROFL");
}];
for the record, I have tried the same method with a different signature (without the returning variable name like so :
+(void)requestSuggestedLocationsForText:(NSString*)text withBlock:(void (^)(NSArray*))block;
still didn't fire my breakpoint :(
I think that this:
if ([responseString respondsToSelector:#selector(JSONObjectWithData:options:error:)])
{
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&err];
NSArray * predictions = [json valueForKey:#"predictions"];
block(predictions);
}
Never runs because as far as I know, NSString doesn't declare JSONObjectWithData. Your break point will never hit because it will never be called.
It seems like it could just be:
NSData * responseData = [NSData dataWithData:responseObject];
NSError *err;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&err];
if (!err) {
NSArray * predictions = [json valueForKey:#"predictions"];
block(predictions);
}
else {
block(nil);
}
The other way you convert it to a string, then back to data, why not just keep it as data?

Resources