Wait the function run finish only get the data [duplicate] - ios

This question already has an answer here:
Storing values in completionHandlers - Swift
(1 answer)
Closed 7 years ago.
I have a function that get data from server and it will run asynchronous while other function is running.
my problem, i called the function [self getdata] at viewdidload(). and NSLog at below the called function but the data is delay. it get null. may i know anyway to wait the function run finish only print out the data for me?
-(void)getdata
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *userID = [prefs objectForKey:#"userID"];
//get merged news
float latitude = [[prefs objectForKey:LAST_KNOWN_LATITUDE] floatValue];
float longitude = [[prefs objectForKey:LAST_KNOWN_LONGITUDE] floatValue];
NSInteger ref_id =[[[eventDict objectForKey:#"id"] substringFromIndex:2]integerValue];
NSInteger reference_EventType = [[eventDict objectForKey:#"type_id"]integerValue];
NSString *type =#"EVENT";
NSString *str = [NSString stringWithFormat:#"%#event.php", API_URL];
NSURL *URL = [NSURL URLWithString:str];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:URL];
__unsafe_unretained ASIFormDataRequest *_request = request;
[request setRequestMethod:#"POST"];
[request setPostValue:#"get_event_notification" forKey:#"tag"];
[request setPostValue:[NSNumber numberWithInteger:ref_id] forKey:#"reference_id"];
[request setPostValue:[NSNumber numberWithInteger:reference_EventType] forKey:#"reference_eventType"];
[request setPostValue:type forKey:#"reference_type"];
[request setPostValue:[NSNumber numberWithFloat:latitude] forKey:#"latitude"];
[request setPostValue:[NSNumber numberWithFloat:longitude] forKey:#"longitude"];
[request setPostValue:userID forKey:#"user_id"];
[request setDelegate:self];
[request setTimeOutSeconds:30.0];
[request setShouldAttemptPersistentConnection:NO];
[request startAsynchronous];
[request setCompletionBlock:^(void){
NSInteger responseCode = [_request responseStatusCode];
if (responseCode == 200 || responseCode == 201 || responseCode == 202)
{
//NSLog(#"%#", [_request responseString]);
NSMutableDictionary *response = (NSMutableDictionary *)[[_request responseString] JSONValue];
NSInteger success = [[response objectForKey:#"success"] integerValue];
if (success == 1)
{
if ([[response objectForKey:#"event"] isKindOfClass:[NSArray class]]) {
event = [[response objectForKey:#"event"] objectAtIndex:0];
dataArray=[event objectForKey:#"merged"];
NSLog(#"dataArray %d",dataArray.count);
mergedCount=[NSString stringWithFormat:#"%d",dataArray.count];
NSArray *pathsMergedCount = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryMergedCount = [pathsMergedCount objectAtIndex:0];
NSString *filePathMergedCount= [documentsDirectoryMergedCount stringByAppendingPathComponent:#"fileMergedCount.txt"];
[mergedCount writeToFile:filePathMergedCount atomically:TRUE encoding:NSUTF8StringEncoding error:NULL];
for(i=0;i<[dataArray count];i++)
{
feedDict=[dataArray objectAtIndex:i];
[eventIDMerged addObject:[feedDict objectForKey:#"event_id"]];
[eventDescMerged addObject:[feedDict objectForKey:#"description"]];
}
}}}
}];
[request setFailedBlock:^(void){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Failed" message:#"Internet connection too slow, please ensure you have a strong internet connection to have better user experience" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}];
}
-(void)viewDidLoad
{
[self getdata];
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *pathsMergedCount = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryMergedCount = [pathsMergedCount objectAtIndex:0];
NSString *filePathMergedCount= [documentsDirectoryMergedCount stringByAppendingPathComponent:#"fileMergedCount.txt"];
NSString *strMergedCount = [NSString stringWithContentsOfFile:filePathMergedCount encoding:NSUTF8StringEncoding error:NULL];
NSLog(#"Count3m %#",strMergedCount);
});
});
}

See my answer in this thread:
Storing values in completionHandlers - Swift
It includes a link to a full project (in Swift) demonstrating using completion handlers to manage async tasks.

Related

Return NSMutableArray from completionHandler (Objective C)

I did post request to a web service and get response. I convert the response to NSMutableArray. My response in NSURLSessionDataTask and now I want to return NSMutableArray for using outside of NSURLSessionDataTask. Here is my code:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"url"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSString *postString = #"params";
NSString *postLength = [NSString stringWithFormat:#"%lu", ( unsigned long )[postString length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length" ];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask *task = [[self getURLSession] dataTaskWithRequest:request completionHandler:^( NSData *data, NSURLResponse *response, NSError *error )
{
dispatch_async( dispatch_get_main_queue(),
^{
NSDictionary *dicData = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:nil];
NSDictionary *values = [dicData valueForKeyPath:#"smth"];
NSArray * dataArr = [dicData objectForKey:#"smth"];
NSArray * closeArr = [values objectForKey:#"0"];
NSUInteger dataCount = [dataArr count] ;
NSUInteger closeCount = [closeArr count] ;
NSMutableArray * newData = [NSMutableArray new] ; //<-- THIS ARRAY
for(int i = 0 ; i<dataCount && i<closeCount ; i++)
{
NSMutableDictionary * temp = [NSMutableDictionary new] ;
NSString * dataString = [dataArr objectAtIndex:i];
NSString * closeString = [closeArr objectAtIndex:i];
[temp setObject:dataString forKey:#"smth"];
[temp setObject:closeString forKey:#"smth"];
[newData addObject:temp];
}
NSLog(#"%#", newData);
} );
}];
[task resume];
I need return NSMutableArray * newData = [NSMutableArray new];
Long story short, I get json data from web service, then transform it to appropriate json format for displaying it in the chart(I use shinobicontrols). Now, I display chart with the help of local json. Here is the code:
_timeSeries = [NSMutableArray new];
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"AppleStockPrices" ofType:#"json"];
NSData* json = [NSData dataWithContentsOfFile:filePath];
NSArray* data = [NSJSONSerialization JSONObjectWithData:json
options:NSJSONReadingAllowFragments
error:nil];
for (NSDictionary* jsonPoint in data) {
SChartDataPoint* datapoint = [self dataPointForDate:jsonPoint[#"smth1"]
andValue:jsonPoint[#"smth2"]];
[_timeSeries addObject:datapoint];
}
When I am trying to implement this code in NSURLSessionDataTask, the chart doesn't appear. So I need return NSMutableArray(where my data in appropriate json format) outside.
How can I do this? Any ideas?
Thank you!
You cannot add a return statement in the completion handler since it may not be called if the session return an error. As a matter of fact, Xcode will give you an "Incompatible pointer type" error if you try to do that.
The best way I found to go around it is to set up your newData array as a property and make it available to the other methods in the class. If a specific method will need to handle this array when the url session task is over, you can call that method from the completion handler or use a notification.
Alternatively, if for some reason you do not want to user a class property, you can use the NSNotificationCenter, and pass the newData to the listener in the notification object.
EDIT: code example using a property
If you need the newData outside the completion block, an easy way is declaring the array as a property. This is not the only approach and probably not the best. But it doesn't add much complexity to the code.
You can declare the newData array in your .m class file:
#interface "whatever class you are using"
#property (nonatomic, strong) NSMutableArray *newData;
#end
Your can initialize the array in your viewDidLoad method:
- (void)viewDidLoad {
_newdata = [[NSMutableArray alloc] init];
}
In Your completion block, you would remove the initialization and add data to the array.
//NSMutableArray * newData = [NSMutableArray new] ; // REMOVE THE INTIALIZATION
for(int i = 0 ; i<dataCount && i<closeCount ; i++) {
NSMutableDictionary * temp = [NSMutableDictionary new] ;
NSString * dataString = [dataArr objectAtIndex:i];
NSString * closeString = [closeArr objectAtIndex:i];
[temp setObject:dataString forKey:#"smth"];
[temp setObject:closeString forKey:#"smth"];
[_newData addObject:temp];
}
Again, this is not the best approach but it is relatively simple. One problem with doing this, is that since you have a strong reference to the array, if you need to perform another URL call, and load new data into the array, you will need to empty it. Otherwise, the new data will be appended to the old one. You can do it by calling [_newData removeAllObjects]; before the URL session is called again.
EDIT 2: changed code based on the user comment:
- (void)loadChartData {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"url"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSString *postString = #"params";
NSString *postLength = [NSString stringWithFormat:#"%lu", ( unsigned long )[postString length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length" ];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask *task = [[self getURLSession] dataTaskWithRequest:request completionHandler:^( NSData *data, NSURLResponse *response, NSError *error ) {
dispatch_async( dispatch_get_main_queue(), ^{
NSDictionary *dicData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSDictionary *values = [dicData valueForKeyPath:#"smth"];
NSArray * dataArr = [dicData objectForKey:#"smth"];
NSArray * closeArr = [values objectForKey:#"smth0"];
NSUInteger dataCount = [dataArr count] ;
NSUInteger closeCount = [closeArr count] ;
NSMutableArray * newData = [NSMutableArray new] ;
for(int i = 0 ; i<dataCount && i<closeCount ; i++) {
NSMutableDictionary * temp = [NSMutableDictionary new] ;
NSString * dataString = [dataArr objectAtIndex:i];
NSString * closeString = [closeArr objectAtIndex:i];
[temp setObject:dataString forKey:#"smth"];
[temp setObject:closeString forKey:#"smth"];
[newData addObject:temp];
}
NSLog(#"%#", newData);
_timeSeries = [NSMutableArray new];
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"AppleStockPrices" ofType:#"json"];
NSData* json = [NSData dataWithContentsOfFile:filePath];
NSArray* data = [NSJSONSerialization JSONObjectWithData:json options:NSJSONReadingAllowFragments error:nil];
for (NSDictionary* jsonPoint in data) {
SChartDataPoint* datapoint = [self dataPointForDate:jsonPoint[#"smth"] andValue:jsonPoint[#"smth"]];
[_timeSeries addObject:datapoint];
}
});
}];
[task resume];
// Code here has a good chance of being executed before the completion block is complete
// _newdata = [[NSMutableArray alloc] init];
// NSLog(#"%#", _newdata);
}

Payu money Payment GateWay Integration

I am trying to integrate payu money payment gateway in my app.
Payumoney collect all information and done transaction and return back to my custom defined url webpage.
My problem is how to get the response code after successful transaction from payu money gateway?
int i = arc4random() % 9999999999;
NSString *strHash = [self createSHA512:[NSString stringWithFormat:#"%d%#",i,[NSDate date]]];
NSString *txnid1 = [strHash substringToIndex:20];
NSLog(#"tnx1 id %#",txnid1);
// NSString *key = #"JBZaLc";
// NSString* salt = #"GQs7yium";
NSString *key = #"gtKFFx";
NSString* salt = #"eCwWELxi";
NSString *amount = dataMoney.usrAmount;
NSString *productInfo = #"App Products Info ";
NSString *firstname = dataMoney.usrName;
NSString *email = dataMoney.usrEmail;
NSString *phone = dataMoney.usrMobile;
NSString *surl = #"https://dl.dropboxusercontent.com/s/dtnvwz5p4uymjvg/success.html";
NSString *furl = #"https://dl.dropboxusercontent.com/s/z69y7fupciqzr7x/furlWithParams.html";
NSString *hashValue = [NSString stringWithFormat:#"%#|%#|%#|%#|%#|%#|||||||||||%#",key,txnid1,amount,productInfo,firstname,email,salt];
NSString *hash = [self createSHA512:hashValue];
NSDictionary *parameters = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:txnid1,key,amount,productInfo,firstname,email,phone,surl,furl,hash, nil] forKeys:[NSArray arrayWithObjects:#"txnid",#"key",#"amount",#"productinfo",#"firstname",#"email",#"phone",#"surl",#"furl",#"hash", nil]];
__block NSString *post = #"";
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([post isEqualToString:#""]) {
post = [NSString stringWithFormat:#"%#=%#",key,obj];
}else{
post = [NSString stringWithFormat:#"%#&%#=%#",post,key,obj];
}
}];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://test.payu.in/_payment"]]];
// change URL for live
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Current-Type"];
[request setHTTPBody:postData];
[web_view_PayU loadRequest:request];
#define Merchant_Key #"your merchant key "
#define Salt #"your salt key"
#define Base_URL #"https://secure.payu.in"
> //this base url in case of origional payment key's if you want to integarate with
test key's write base Url can check in payumoney Faq
**
#define Success_URL #"https://www.google.co.in/"
#define Failure_URL #"http://www.bing.com/"
#define Product_Info #"Denim Jeans"
#define Paid_Amount #"1549.00"
#define Payee_Name #"Suraj Mirajkar"
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
[self setTitle:#"Make A Payment"];
[self initPayment];
}
- (void)viewDidLoad {
[super viewDidLoad];
activityIndicatorView = [[UIActivityIndicatorView alloc] init];
activityIndicatorView.center = self.view.center;
[activityIndicatorView setColor:[UIColor blackColor]];
[self.view addSubview:activityIndicatorView];
}
-(void)initPayment {
int i = arc4random() % 9999999999;
NSString *strHash = [self createSHA512:[NSString stringWithFormat:#"%d%#",i,[NSDate date]]];// Generatehash512(rnd.ToString() + DateTime.Now);
NSString *txnid1 = [strHash substringToIndex:20];
strMIHPayID = txnid1;
NSString *key = Merchant_Key;
NSString *amount =[[NSUserDefaults standardUserDefaults]
stringForKey:#"orderprice"];
//NSString *amount = Paid_Amount;
NSString *productInfo = Product_Info;
NSString *firstname = Payee_Name;
NSString *email = [NSString stringWithFormat:#"suraj%d#yopmail.com",i];
//ADD A fake mail For Payment for testing purpose
// Generated a fake mail id for testing
NSString *phone = #"9762159571";
NSString *serviceprovider = #"payu_paisa";
NSString *hashValue = [NSString stringWithFormat:#"%#|%#|%#|%#|%#|%#|||||||||||%#",key,txnid1,amount,productInfo,firstname,email,Salt];
NSString *hash = [self createSHA512:hashValue];
NSDictionary *parameters = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:txnid1,key,amount,productInfo,firstname,email,phone,Success_URL,Failure_URL,hash,serviceprovider
, nil] forKeys:[NSArray arrayWithObjects:#"txnid",#"key",#"amount",#"productinfo",#"firstname",#"email",#"phone",#"surl",#"furl",#"hash",#"service_provider", nil]];
NSLog(#"%#",parameters);
__block NSString *post = #"";
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([post isEqualToString:#""]) {
post = [NSString stringWithFormat:#"%#=%#",key,obj];
} else {
post = [NSString stringWithFormat:#"%#&%#=%#",post,key,obj];
}
}];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/_payment",Base_URL]]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Current-Type"];
[request setHTTPBody:postData];
[_webviewPaymentPage loadRequest:request];
[activityIndicatorView startAnimating];
}
-(NSString *)createSHA512:(NSString *)string {
const char *cstr = [string cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:string.length];
uint8_t digest[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(data.bytes, (CC_LONG)data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++) {
[output appendFormat:#"%02x", digest[i]];
}
return output;
}
#pragma UIWebView - Delegate Methods
-(void)webViewDidStartLoad:(UIWebView *)webView {
NSLog(#"WebView started loading");
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicatorView stopAnimating];
if (webView.isLoading) {
return;
}
NSURL *requestURL = [[_webviewPaymentPage request] URL];
NSLog(#"WebView finished loading with requestURL: %#",requestURL);
NSString *getStringFromUrl = [NSString stringWithFormat:#"%#",requestURL];
if ([self containsString:getStringFromUrl :Success_URL]) {
[self performSelector:#selector(delayedDidFinish:) withObject:getStringFromUrl afterDelay:0.0];
} else if ([self containsString:getStringFromUrl :Failure_URL]) {
// FAILURE ALERT
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Sorry !!!" message:#"Your transaction failed. Please try again!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
alert.tag = 1;
[alert show];
}
}
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[activityIndicatorView stopAnimating];
NSURL *requestURL = [[_webviewPaymentPage request] URL];
NSLog(#"WebView failed loading with requestURL: %# with error: %# & error code: %ld",requestURL, [error localizedDescription], (long)[error code]);
if (error.code == -1009 || error.code == -1003 || error.code == -1001) { //error.code == -999
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Oops !!!" message:#"Please check your internet connection!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
alert.tag = 1;
[alert show];
}
}
- (void)delayedDidFinish:(NSString *)getStringFromUrl {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableDictionary *mutDictTransactionDetails = [[NSMutableDictionary alloc] init];
[mutDictTransactionDetails setObject:strMIHPayID forKey:#"Transaction_ID"];
[mutDictTransactionDetails setObject:#"Success" forKey:#"Transaction_Status"];
[mutDictTransactionDetails setObject:Payee_Name forKey:#"Payee_Name"];
[mutDictTransactionDetails setObject:Product_Info forKey:#"Product_Info"];
[mutDictTransactionDetails setObject:Paid_Amount forKey:#"Paid_Amount"];
[self navigateToPaymentStatusScreen:mutDictTransactionDetails];
});
}
#pragma UIAlertView - Delegate Method
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.tag == 1 && buttonIndex == 0) {
// Navigate to Payment Status Screen
NSMutableDictionary *mutDictTransactionDetails = [[NSMutableDictionary alloc] init];
[mutDictTransactionDetails setObject:Payee_Name forKey:#"Payee_Name"];
[mutDictTransactionDetails setObject:Product_Info forKey:#"Product_Info"];
[mutDictTransactionDetails setObject:Paid_Amount forKey:#"Paid_Amount"];
[mutDictTransactionDetails setObject:strMIHPayID forKey:#"Transaction_ID"];
[mutDictTransactionDetails setObject:#"Failed" forKey:#"Transaction_Status"];
[self navigateToPaymentStatusScreen:mutDictTransactionDetails];
}
}
- (BOOL)containsString: (NSString *)string : (NSString*)substring {
return [string rangeOfString:substring].location != NSNotFound;
}
- (void)navigateToPaymentStatusScreen: (NSMutableDictionary *)mutDictTransactionDetails {
dispatch_async(dispatch_get_main_queue(), ^{
PaymentStatusViewController *paymentStatusViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"PaymentStatusScreenID"];
paymentStatusViewController.mutDictTransactionDetails = mutDictTransactionDetails;
[self.navigationController pushViewController:paymentStatusViewController animated:YES];
});
}
Important Note : you can check your Merchant key and Salt in seller Dashboard after Login ... Go To my account and check your merchant key and salt

NSXML XML Parsing issue iOS

I know that there are plenty of questions that have been asked and answered and non of them pertain to my problem.
I am posting XML to a server and I get a response back. My problem is getting a specified key back from the response.
I am trying to list all Genders e.g Male, Female and their id's however when parsing the XML into text with NSXML I only get back the Female and ID 2 and I do not get back Male?
I have researched and tried to fix this issue but to no avail.
here is my code:
- (void)getGender {
NSString *soapMessage = [NSString stringWithFormat:
#"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:app=\"http://app.ws.api.bells.wigroup.com/\">"
"<soap:Header/>\n"
"<soap:Body>\n"
"<app:getAllGenders>\n"
"<request>\n"
"<apiCredentials>\n"
"<apiId>IPHONE_APP</apiId>\n"
"<sha1Password>8656cafcd71cbbfe773a0fdb6c422666a80e5b8f</sha1Password>\n"
"</apiCredentials>\n"
"<request>\n"
"</request>\n"
"</request>\n"
"</app:getAllGenders>\n"
"</soap:Body>\n"
"</soap:Envelope>\n"
];
NSLog(#"Message%#",soapMessage);
NSURL *url = [NSURL URLWithString:#"http://qa.wigroup.co:8080/bells/AppWS"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d", [soapMessage length]];
[theRequest addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
//[theRequest addValue: #"http://" forHTTPHeaderField:#"SOAPAction"];
[theRequest addValue: msgLength forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection )
{
NSURLResponse *response;
NSError *error;
NSData *urlData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Login response XML:%#",str);
// create and init NSXMLParser object
XmlArrayParser *parser = [[XmlArrayParser alloc] initWithData:urlData];
parser.rowElementName = #"return";
parser.elementNames = [NSArray arrayWithObjects:#"response", #"responseCode", #"responseDesc", #"gendersList", nil];
parser.attributeNames = [NSArray arrayWithObjects:#"id", #"gender", nil];
if ([parser.rowElementName isEqualToString:#"responseCode"] && _flag)
{
//read the value here
NSLog(#"flagging");
}
// parsing...
BOOL success = [parser parse];
// test the result
if (success)
{
NSMutableArray *loginAuth = [parser items];
// self.textView.text = [NSString stringWithFormat:
// #"This is an array of dictionaries, one dictionary for each user:\n\n%#",
// [users description]];
// NSDictionary *eventLocation = [NSDictionary dictionaryWithObjectsAndKeys:#"response", nil];
NSDictionary *loginResponse = [loginAuth objectAtIndex:0]; // this retrieves the first user
NSString *userResponse = loginResponse[#"gendersList"]; // this retrieves that user's username in Xcode 4.5 and greater
NSString *userRes = [loginResponse objectForKey:#"id"];
NSString *test = [loginAuth description];
NSLog(#"Returned Code loginResponse %#",loginResponse);
NSLog(#"Returned Code userResponse %# %#",userResponse, userRes);
NSLog(#"Returned Code test %#",test);
NSMutableArray *array=[[NSMutableArray alloc]initWithCapacity:10];
for (NSDictionary *defineXMLData in loginAuth) {
NSNumber * responseCode = [defineXMLData objectForKey:#"responseCode"];
NSArray * responseDEsc = [defineXMLData objectForKey:#"responseDesc"];
NSArray * genderList = [defineXMLData objectForKey:#"gendersList"];
// NSArray * gender = [defineJsonData objectForKey:#"gender"];
NSLog(#"Genders%#", genderList);
[array addObject: responseCode];
[array addObject: responseDEsc];
[array addObject: genderList];
//[array addObject: gender];
// [array addObject: vouchersUser];
}
label.numberOfLines = 2000; // for example
label.lineBreakMode = NSLineBreakByClipping;
NSString *output=[array componentsJoinedByString:#","];
label.text = [NSString stringWithFormat:#"XML Result: %# ",output];
[SVProgressHUD dismiss];
// [[[UIAlertView alloc] initWithTitle:nil
// message:[NSString stringWithFormat:#"No errors - user count : %i", [[parser items] count]]
// delegate:nil
// cancelButtonTitle:#"OK"
// otherButtonTitles:nil] show];
}
else
{
NSLog(#"Error parsing document!");
// [[[UIAlertView alloc] initWithTitle:nil
// message:#"Error parsing document!"
// delegate:nil
// cancelButtonTitle:#"OK"
// otherButtonTitles:nil] show];
}
}
else
{
NSLog(#"theConnection is NULL");
}
NSLog(#"test");
}
And the XML I get back from my nslog:
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getAllGendersResponse xmlns:ns2="http://app.ws.api.bells.wigroup.com/">
<return>
<responseCode>-1</responseCode>
<responseDesc>Success</responseDesc>
<response>
<responseCode>-1</responseCode>
<responseDesc>Success</responseDesc>
<gendersList>
<gender>Male</gender>
<id>1</id>
</gendersList>
<gendersList>
<gender>Female</gender>
<id>2</id>
</gendersList>
</response>
Is only parsing:
{
gendersList = Female2;
responseCode = "-1";
responseDesc = Success;
}
You have not correctly pointed the problem. Your code parses the whole document, but you keep only the last items (last genderList, last responseCode, last responseDesc). Initialize an array and in your for loop add each dictionary to that array when parsed.

iOS : Query regarding dynamically created array

I get four parameters from a web service (web service 2 in my flow) - slno, order, flag, name. I don't know how many times these parameters are going to be received. Out of these four paramters, I send 'name' to a label as it contains questions to be asked.
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"some url"]];
NSLog(#"Web service 2 url is = %#", url);
NSString *json = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:&error];
NSLog(#"Json data = %# \n error = %#", json, error);
if(!error)
{
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *myJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:Nil];
//NSArray *arrayLabel = [[NSArray alloc] initWithObjects:label1, label2, label3, label4, label5, label6, nil];
//NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:myJsonArray.count];
i = 0;
for(NSDictionary *myJsonDictionary in myJsonArray)
{
//UILabel *label = (UILabel *)[arrayLabel objectAtIndex:i++];
//[label setText:myJsonDictionary[#"Name"]];
NSString *name = myJsonDictionary[#"Name"];
NSLog(#"Question from ws2 is %#", name);
projectIdGobal = myJsonDictionary[#"ProjectID"];
NSLog(#"Project id from ws2 is %#", projectIdGobal);
slno = myJsonDictionary[#"SLNO"];
NSLog(#"slno from ws2 is %#", slno);
NSString *idWS2 = myJsonDictionary[#"ID"];
NSLog(#"id from ws2 is %#", idWS2);
order = myJsonDictionary[#"Order"];
NSLog(#"order from ws2 is %#", order);
flag = myJsonDictionary[#"Flag"];
NSLog(#"flag from ws2 is %#", flag);
[self putLabelsInScrollView:name];
i++;
}
NSLog(#"Number of cycles in for-each = %d", i);
[activity stopAnimating];
}
- (void) putLabelsInScrollView:(NSString *)labelText
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, yPosition_label, 261, 30)];
[label setFont:[UIFont fontWithName:#"Helvetica Neue" size:12.0f]];
label.numberOfLines = 2;
[label setText:labelText];
[self.scroll addSubview:label];
yPosition_label += 90;
UITextField *text = [[UITextField alloc] initWithFrame:CGRectMake(10, yPosition_text, 261, 30)];
text.borderStyle = UITextBorderStyleRoundedRect;
text.textColor = [UIColor blackColor];
text.font = [UIFont systemFontOfSize:12.0];
text.backgroundColor = [UIColor clearColor];
text.keyboardType = UIKeyboardTypeDefault;
text.delegate = self;
[self.scroll addSubview:text];
yPosition_text += 90;
yPosition_result = yPosition_label + yPosition_text;
[self.scroll setContentSize:CGSizeMake(self.scroll.frame.size.width, yPosition_result)];
[self.view addSubview:self.scroll];
}
Now I created a dynamically created text fields and stored the answers entered by the user in the array as follows.
- (IBAction)save:(id)sender {
NSMutableArray *mutableTextArray = [[NSMutableArray alloc] init];
for(UITextField *field in self.scroll.subviews)
{
if([field isKindOfClass:[UITextField class]])
{
if([[field text] length] > 0)
{
[mutableTextArray addObject:field.text];
//NSLog(#"Save button 1 : %#", mutableTextArray);
//NSString *str = [str stringByAppendingString:[mutableTextArray objectAtIndex:0]];
//[self fetchStrings:mutableTextArray];
}
}
}
NSLog(#"Save button 2 : %#", mutableTextArray);
[self fetchStrings:mutableTextArray];
}
Now while posting the answer to another web service (web service 3 in my flow), I must pass slno, order, flag i get from web service 2 and the 'answer' that the user enters in the dynamically created field to the 'answer' key. How shall I get these 4 parameters [slno, order, flag (from web service 2) and answer (from dynamic text field)] to post to web service 3?
- (void) fetchStrings:(NSArray *)textArray
{
NSLog(#"Array string = %#", textArray); //I get the array that the user enters in the dynamically created text field here
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSUserDefaults *getDefaults = [NSUserDefaults standardUserDefaults];
NSString *uidObject = [getDefaults objectForKey:#"UIDKEY"];
NSString *str = [NSString stringWithFormat:#"{\"ProjID\": \"%#\",\"Uid\": \"%#\",\"EmailID\": \"%#\",", projectIdGobal, uidObject, emailFromLogin];
str = [str stringByAppendingString:#"\"ProjectInviterFQAnswers\": ["];
**for (SaveAsking *saveAsk in textArray) {
str = [str stringByAppendingString:[NSString stringWithFormat:#"{\"slno\":\"%#\",\"Answer\": \"%#\",\"order\": \"%#\", \"flag\": \"%#\"},", saveAsk.slno, saveAsk.answer, saveAsk.order, saveAsk.flag]]; // I want to save the parameters here
}**
// SaveAsking is a nsobject class where I have used a self created delegate for slno answer order and flag
str = [str stringByAppendingString:#"]}"];
NSLog(#"String is === %#", str);
NSURL *url = [NSURL URLWithString:#"some url"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [str dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if(error || !data)
{
NSLog(#"JSON Data not posted!");
[activity stopAnimating];
UIAlertView *alertMessage = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Data not saved" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertMessage show];
}
else
{
[activity startAnimating];
NSLog(#"JSON data posted! :)");
NSError *error = Nil;
NSJSONSerialization *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSLog(#"Response is %#", jsonObject);
}
}];
}
Please do correct my flow if you understood what am i trying to achieve. Number for iterations in left box == number of iterations in right box and the result is in the middle box which needs to be posted to web service.
Try keeping a dictionary of the requests, where the key would be the dynamically created UITextField, and the value would be another dictionary with the values that you need to send.
So , when you create the textField, after adding it to the subview, create a dictionary with your values (sino, order, flag), and set that dictionary to the textfield.
When you are ready to send the data, you'll have a direct connection between the textField and the values for your webservice3.

iOS Check for Token

I'm making an app that requires you to login in. I"m using JSON. So far I've been able send a POST request with the Username and Password and I get a token back (it shows up in the console). When I don't enter in the correct username/password combination, I don't get a token back. What I would like to happen is to proceed to the next view controller if I get a token back. I think that I need to use an if statement (I'll put the code for switching view controllers into it) but I don't know what parameters I need in order to check if I get a token back.
Here is the code I'm using in the implementation file. It is in a method that runs when a button is pressed:
#try {
if([[usernameTextField text] isEqualToString:#""] || [[passTextField text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter both Username and Password" :#"Login Failed!"];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"username=%#&password=%#",[usernameTextField text],[passTextField text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"https://beta.network360.com/tokens"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1)
{
NSLog(#"Login SUCCESS");
[self alertStatus:#"Logged in Successfully." :#""];
} else {
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Login Failed!"];
}
} else {
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#""];
}
}
}
#catch (NSException * e)
{
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#""];
//[[PSearchViewController new] performSegueWithIdentifier:#"loginCancel" sender:self];
}
Also, here is what I get in the console output when I put in the correct username/password combination (BTW I tried to change all the stuff that showed up in the console that was confidential, so if some stuff doesn't quite match, it should be fine. I just wanted to show that I get a token back):
2013-07-28 13:23:21.607 Empyrean[28283:c07] PostData: username=username#gmail.com&password=password
2013-07-28 13:23:22.300 Empyrean[28283:c07] Response code: 200
2013-07-28 13:23:22.301 Empyrean[28283:c07] Response ==> {"token":"scFDzxSAVk2sxQBShEGS","user":{"id":300230,"username":"username#gmail.com","display_name":"FirstName LastName","unconfirmed_email":null,"email":"username#gmail.com","confirmation_email":"username#gmail.com","client_identifier":null,"client_id":138,"is_admin":false,"support_email":"support#supportemail.com","application_name":"AppName","show_project_vintage_date":false,"is_anonymous":false,"is_active":true,"is_confirmed":true,"pending_reconfirmation":false,"can_resend_confirmation":false,"client_name":"Broker","show_advertisements":true,"header_logo":"/foo/headerlogo.gif","report_footer_logo":"/stuff/foo/footerlogo.png","authorized_features":["find_stuff","do_stuff","stuff_stuff","settings","menu","manage_stuff","measure_stuff","export_stuff"],"url":"https://www.website.com/stuff/numbersdsjkflds"}}
2013-07-28 13:23:22.304 Empyrean[28283:c07] {
token = dlsfkasdfDfdsklfdDsa;
user = {
"application_name" = "Application Name";
"authorized_features" = (
"find_stuff",
"do_stuff",
"stuff_stuff",
settings,
menu,
"manage_stuff",
"measure_stuff",
"export_stuff"
);
"can_resend_confirmation" = 0;
"client_id" = 138;
"client_identifier" = "<null>";
"client_name" = Broker;
"confirmation_email" = "username#gmail.com";
"display_name" = "FirstName LastName";
email = "username#gmail.com";
"url" = "https://www.website.com/stuff/numbersdsjkflds";
"header_logo" = "/foo/headerlogo.gif";
id = 300230;
"is_active" = 1;
"is_admin" = 0;
"is_anonymous" = 0;
"is_confirmed" = 1;
"pending_reconfirmation" = 0;
"report_footer_logo" = "/stuff/foo/footerlogo.png";
"show_advertisements" = 1;
"show_project_vintage_date" = 0;
"support_email" = "support#supportemail.com";
"unconfirmed_email" = "<null>";
username = "username#gmail.com";
};
}
NSDictionary *jsonData is a dictionary. Therefore, you can see if the token key exists.
if (jsonData[#"token"])
{
// Token exists, so move on.
[self.navigationController pushViewController:nextController animated:YES];
}
else
{
// Tell the user they messed it up.
}

Resources