The app keeps score during a game. Based off of your score, it will retrieve a quote from an online database, using a GET method and returning it in JSON format. For example, your score is 5, you get 1 quote, 10, you get 2 and so on. The view that shows the quote(s) is a UIViewController with a UITextView in it.
I have a for loop that runs based off the score, to run the same GET request over and over again, after a 1.5 second delay so the server housing the database won't reject requests made nearly simultaneously.
I create a few NSStrings and pull information from the JSON data, append it into some basic HTML code and then set that as the UITextView attributedText.
Most of the time this runs great, but every once in a while, I'll expect 2 quotes, and only get 1, or some of the quotes will wind up being the same.
Can someone tell me if there is a better way to go about doing this than how I currently am?
- (void)viewWillAppear:(BOOL)animated {
if ([textView.text isEqualToString:#""]) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger getReady = [defaults integerForKey:#"after"];
self.theNumber = getReady;
for(int i = 0; i< self.theNumber; i++) {
[self performSelector:#selector(quoteView) withObject:self afterDelay:1.5 ];
}
}
}
-(void) quoteView {
NSString *bringitalltogether = #"http://url.com&type=json";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:bringitalltogether]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
[request setHTTPMethod:#"GET"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]])
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
if (code == 200){
}
else
{
UIAlertView *oops = [[UIAlertView alloc] initWithTitle:#"Oops" message:#"The network is having difficulties getting you the quote. Please check your network settings and try again later." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[oops show];
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSMutableDictionary *allResults = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:nil];
NSArray *book = [allResults valueForKey:#"bookname"];
self.bookstring = [book objectAtIndex:0];
NSArray *chapter = [allResults valueForKey:#"chapter"];
self.chapterstring = [chapter objectAtIndex:0];
NSArray *verse = [allResults valueForKey:#"verse"];
self.versestring = [verse objectAtIndex:0];
NSArray *text = [allResults valueForKey:#"text"];
self.textstring = [text objectAtIndex:0];
[self doneGotIt];
}
- (void) doneGotIt {
if (!self.theArray) {
self.theArray = [[NSMutableArray alloc] init];
}
NSString *doIt = [NSString stringWithFormat:#"%# - %# %#:%#", self.textstring, self.bookstring, self.chapterstring, self.versestring];
[self.theArray addObject:doIt];
NSString *theEnd = [self.theArray componentsJoinedByString:#"\n"];
NSString *loadHTML = [#"<head> <style type='text/css'>a > img {pointer-events: none;cursor: default;}</style></head><b><div align=\"left\"><font size=5>" stringByAppendingString:theEnd];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:[loadHTML dataUsingEncoding:NSUnicodeStringEncoding] options:#{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
textView.attributedText = attributedString;
NSLog(#"ARRAY: %#", self.theArray);
NSLog(#"String: %#", theEnd);
}
-(IBAction)finished {
[self dismissViewControllerAnimated:YES completion:nil];
textView = nil;
}
From the NSLogs I have towards the end there, sometimes the NSMutableArray contains several of the same quotes, which is why they don't show in the string, because it eliminates duplicates. My question is if there is a better way to do this that will keep these errors from occurring?
Here is some pseudo code for you
mutableArray = new NSMutableArray
while([mutableArray count] < total) {
quote = getQuote()
if([array indexOfObject:quote] != NSNotFound)
[mutableArray addObject:quote]
}
This will ensure you do not have duplicate quotes. After you have an array of valid quotes, you can then construct the string exactly how you want it.
Related
I need to display particular object for key(currency) using post method after getting response from web.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController{
NSMutableData *mutableData;
NSMutableString *arr;
#define URL #"website"
// change this URL
#define NO_CONNECTION #"No Connection"
#define NO_VALUES #"Please enter parameter values"
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(IBAction)sendDataUsingPost:(id)sender{
[self sendDataToServer :#"POST"];
}
-(IBAction)sendDataUsingGet:(id)sender{
[self sendDataToServer : #"GET"];
}
-(void) sendDataToServer : (NSString *) method{
NSString *Branchid=#"3";
serverResponse.text = #"Getting response from server...";
NSURL *url = nil;
NSMutableURLRequest *request = nil;
if([method isEqualToString:#"GET"]){
NSString *getURL = [NSString stringWithFormat:#"%#?branch_id=%#", URL, Branchid];
url = [NSURL URLWithString: getURL];
request = [NSMutableURLRequest requestWithURL:url];
NSLog(#"%#",getURL);
}else{ // POST
NSString *parameter = [NSString stringWithFormat:#"branch_id=%#",Branchid];
NSData *parameterData = [parameter dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
url = [NSURL URLWithString: URL];
NSLog(#"%#", parameterData);
request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPBody:parameterData];
arr= [NSMutableString stringWithUTF8String:[parameterData bytes]];
NSLog(#"responseData: %#", arr);
//NSLog(#"%#",[[arr valueForKey:#"BranchByList"]objectForKey:#"currency"]);
}
[request setHTTPMethod:method];
[request addValue: #"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
//NSLog(#"%#",[connection valueForKeyPath:#"BranchByList.currency"]);
if( connection )
{
mutableData = [NSMutableData new];
//NSLog(#"%#",[connection valueForKeyPath:#"BranchByList.currency"]);
}
}
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *)response
{
[mutableData setLength:0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mutableData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
serverResponse.text = NO_CONNECTION;
return;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSMutableString *responseStringWithEncoded = [[NSMutableString alloc] initWithData: mutableData encoding:NSUTF8StringEncoding];
//NSLog(#"Response from Server : %#", responseStringWithEncoded);
NSLog(#"%#",responseStringWithEncoded );
NSLog(#"%#",[responseStringWithEncoded valueForKeyPath:#"BranchByList.currency"] );
NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[responseStringWithEncoded dataUsingEncoding:NSUnicodeStringEncoding] options:#{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
serverResponse.attributedText = attrStr;
// NSLog(#"%#",attrStr);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
i got response branch_id=3 but i want to show to "currency" but i tried lot but failure.
my response like this I need to display only currency.....
Response from Server :
{"BranchByList":
[
{"id":"342","flag_image":"http:\/\/demo.techzarinfo.com\/newantara\/images\/flags\/USD.png","units":"1","code":"USD B","currency":"US DOLLAR BIG","buy":"4.36","sell":"4.395","updated":"2016-04-11 03:24:24"
},
{"id":"342","flag_image":"http:\/\/demo.techzarinfo.com\/newantara\/images\/flags\/USD.png","units":"1","code":"USD B","currency":"US DOLLAR BIG","buy":"4.36","sell":"4.395","updated":"2016-04-11 03:24:24"
}
]};
Your response structure is:
-Dictionary
--Array
---Dictionary Objects
You need to convert your Data into NSDictionary to parse it.
Following code will do that for you:
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData: mutableData
options:kNilOptions
error:&error]; //Now we got top level dictionary
NSArray* responseArray = [json objectForKey:#"BranchByList"]; //Now we got mid level response array
//Get Embeded objects from response Array:
NSDictionary *priceDic = [responseArray objectAtIndex:0]; //Getting first object since you arent telling what the second object is for
NSString *buyingPrice = [priceDic objectForKey: #"buy"]; //Buying price
NSString *sellingPrice = [priceDic objectForKey:#"sell"]; //Selling price
NSString *currency = [priceDic objectForKey:#"currency"]; //Currency
Though this is only sticking to the point and getting the job done.
Proper way to get the job done would be to create a model class for response. Create a class inherited from NSObject and use it as model for this response. Add a initWithDic: method to that class, Pass it your response dic as parameter and delegate all this dictionary parsing to that method.
Also, NSURLConnection is deprecated since iOS 9.0. You should use NSURLSession instead.
Try This May be it will help you:-
NSString *str=[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"str : %#",str);
NSDictionary *dict6 = [self cleanJsonToObject:responseData];
NSLog(#"str : %#",dict6);
NSMArray *array1 = [dict6 objectForKey:#"BranchByList"];
NSLog(#"DICT : %#",array1);
NSDictionary *Dict3 = [array1 objectAtIndex:0];
NSString *Str1 = [dict3 objectForKey:#"currency"];
NSLog(#"Str1 : %#",Str1);
- (id)cleanJsonToObject:(id)data
{
NSError* error;
if (data == (id)[NSNull null])
{
return [[NSObject alloc] init];
}
id jsonObject;
if ([data isKindOfClass:[NSData class]])
{
jsonObject = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
} else
{
jsonObject = data;
}
if ([jsonObject isKindOfClass:[NSArray class]])
{
NSMutableArray *array = [jsonObject mutableCopy];
for (int i = (int)array.count-1; i >= 0; i--)
{
id a = array[i];
if (a == (id)[NSNull null])
{
[array removeObjectAtIndex:i];
} else
{
array[i] = [self cleanJsonToObject:a];
}
}
return array;
} else if ([jsonObject isKindOfClass:[NSDictionary class]])
{
NSMutableDictionary *dictionary = [jsonObject mutableCopy];
for(NSString *key in [dictionary allKeys])
{
id d = dictionary[key];
if (d == (id)[NSNull null])
{
dictionary[key] = #"";
} else
{
dictionary[key] = [self cleanJsonToObject:d];
}
}
return dictionary;
} else
{
return jsonObject;
}
}
I already successfully integrated Google+ to my iOS app. But with the latest Apple store updates, the app is not allowed to open the browser to initiate the Google authentication using safari so i tried uiwebview for googleplus authentication and i am getting the access token but i cannot able to get the username and email address of the person logged in.Below i added my source,
NSString *client_id = #"***************************";;
NSString *secret = #"*******************************";
NSString *callbakc = #"https://www.example.com/oauth2callback";;
NSString *scope = #"https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+https://www.google.com/reader/api/0/subscription";
NSString *visibleactions = #"http://schemas.google.com/AddActivity";
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize webview,isLogin,isReader;
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *url = [NSString stringWithFormat:#"https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%#&redirect_uri=%#&scope=%#&data-requestvisibleactions=%#",client_id,callbakc,scope,visibleactions];
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
}
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
// [indicator startAnimating];
NSLog(#"dgfduiussdiff %# ",[[request URL] host]);
if ([[[request URL] host] isEqualToString:#"www.example.com"]) {
// Extract oauth_verifier from URL query
NSString* verifier = nil;
NSArray* urlParams = [[[request URL] query] componentsSeparatedByString:#"&"];
for (NSString* param in urlParams) {
NSArray* keyValue = [param componentsSeparatedByString:#"="];
NSString* key = [keyValue objectAtIndex:0];
if ([key isEqualToString:#"code"]) {
verifier = [keyValue objectAtIndex:1];
NSLog(#"verifier %#",verifier);
break;
}
}
if (verifier) {
NSString *data = [NSString stringWithFormat:#"code=%#&client_id=%#&client_secret=%#&redirect_uri=%#&grant_type=authorization_code", verifier,client_id,secret,callbakc];
NSString *url = [NSString stringWithFormat:#"https://accounts.google.com/o/oauth2/token"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
receivedData = [[NSMutableData alloc] init];
} else {
// ERROR!
}
[webView removeFromSuperview];
return NO;
}
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSError* error;
[receivedData appendData:data];
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:receivedData
options:kNilOptions
error:&error];
NSLog(#"verifier %#",json);
}
- (void)connection:(NSURLConnection *)connection didFailWithError: (NSError *)error{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[NSString stringWithFormat:#"%#", error]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *response = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
SBJsonParser *jResponse = [[SBJsonParser alloc]init];
NSDictionary *tokenData = [jResponse objectWithString:response];
// WebServiceSocket *dconnection = [[WebServiceSocket alloc] init];
// dconnection.delegate = self;
NSString *pdata = [NSString stringWithFormat:#"type=3&token=%#&secret=123&login=%#", [tokenData objectForKey:#"refresh_token"], self.isLogin];
// NSString *pdata = [NSString stringWithFormat:#"type=3&token=%#&secret=123&login=%#",[tokenData accessToken.secret,self.isLogin];
// [dconnection fetch:1 withPostdata:pdata withGetData:#"" isSilent:NO];
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Google Access TOken"
message:pdata
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
After executing the above source i getting the below response printed in nslog,
verifier 4/kMcSZ2l-d_XXPo24NSdsMnugoP_MGDGPP4D5C1LRTfY
2015-07-21 18:04:16.103 TechnoGerms.com[8981:189233] verifier {
"access_token" = "ya29.twG9kyMElyC8BgAxujF98WKN0BQ246Ey6zsKQEgSpKsNEb5JOS3QRl12La6XBy1geZnL";
"expires_in" = 3600;
"id_token" = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImRhNjYyNWIzNmJjMDlkMzAwMzUzYjI4YTc0MWNlMTc1MjVhNGMzM2IifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTE0MjE4NDEwODI0NzM1ODkyMDg0IiwiYXpwIjoiMTY5NzY2MjI4OTY4LWtoNzI1dTFpZWdzNHN1bnFhOThhcHUxMHU4djhhcmFmLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJhcmp1bkBsaW5rd2FyZS5pbiIsImF0X2hhc2giOiJQVnJxTURpNDViZnVGTm9kTmlsSFlRIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjE2OTc2NjIyODk2OC1raDcyNXUxaWVnczRzdW5xYTk4YXB1MTB1OHY4YXJhZi5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImhkIjoibGlua3dhcmUuaW4iLCJpYXQiOjE0Mzc0ODIwNTUsImV4cCI6MTQzNzQ4NTY1NX0.uSMrV8rOz4T4i5MhiCeQueNVGLv4NBLP-gtOcyow8t4BY9qvUO78sG4y0jPhbclPdX1kUZjzMVTeah2nU9fTYyl50dlj5FzWNy7LyM-a1GC2jEwkgWMgHdRPh6l7dqMrjQ9sU1rF-ZaiWfG7C9VJTJ76uEWRiSKKA9EFQtBil3xBtmDH07UMRxkbri2jBwaCPAWgjU8-dTarrxNESrwrO_nptaRzfGeaTyQBIYCAk6_9deXmblPgteER1OHoa65xb1OVK3ZPeZ3_dj9gjlXSyGp2ho5WIFGf2xRvW4XoROpUYqhLvrS3s-YrrZ8J5X5-3mafrs1qDjJYJogctbW7dg";
"token_type" = Bearer;
}
How i can get the username and email of person logged in by using the access token which i got above ? Please give any suggestions as i dont get any solution on google.
Thanks for your support
if you want to fetch the whole profile of the google+ user, you can use the below URL
https://www.googleapis.com/plus/v1/people/me/?access_token={YOUR_ACCESS_TOKEN}
Then call the GET method. You will be given by an array containing authorized profile details.
Another method is that, if you want to store the authorized users email, its already present in the field as id_token. It is a base64_encoded data with some fields. If you decode the id yo will get some information about the user.For example in your result you found id_token as
eyJhbGciOiJSUzI1NiIsImtpZCI6ImRhNjYyNWIzNmJjMDlkMzAwMzUzYjI4YTc0MWNlMTc1MjVhNGMzM2IifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTE0MjE4NDEwODI0NzM1ODkyMDg0IiwiYXpwIjoiMTY5NzY2MjI4OTY4LWtoNzI1dTFpZWdzNHN1bnFhOThhcHUxMHU4djhhcmFmLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJhcmp1bkBsaW5rd2FyZS5pbiIsImF0X2hhc2giOiJQVnJxTURpNDViZnVGTm9kTmlsSFlRIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjE2OTc2NjIyODk2OC1raDcyNXUxaWVnczRzdW5xYTk4YXB1MTB1OHY4YXJhZi5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImhkIjoibGlua3dhcmUuaW4iLCJpYXQiOjE0Mzc0ODIwNTUsImV4cCI6MTQzNzQ4NTY1NX0.uSMrV8rOz4T4i5MhiCeQueNVGLv4NBLP-gtOcyow8t4BY9qvUO78sG4y0jPhbclPdX1kUZjzMVTeah2nU9fTYyl50dlj5FzWNy7LyM-a1GC2jEwkgWMgHdRPh6l7dqMrjQ9sU1rF-ZaiWfG7C9VJTJ76uEWRiSKKA9EFQtBil3xBtmDH07UMRxkbri2jBwaCPAWgjU8-dTarrxNESrwrO_nptaRzfGeaTyQBIYCAk6_9deXmblPgteER1OHoa65xb1OVK3ZPeZ3_dj9gjlXSyGp2ho5WIFGf2xRvW4XoROpUYqhLvrS3s-YrrZ8J5X5-3mafrs1qDjJYJogctbW7dg
The above id_token contains 2 parts separated by '.'. The first part is thebase64_encoded key and the second part is metadata.
you can decode both the data as
$key=base64_decode(eyJhbGciOiJSUzI1NiIsImtpZCI6ImRhNjYyNWIzNmJjMDlkMzAwMzUzYjI4YTc0MWNlMTc1MjVhNGMzM2IifQ)
will give you the key
$data=base64_decode(eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTE0MjE4NDEwODI0NzM1ODkyMDg0IiwiYXpwIjoiMTY5NzY2MjI4OTY4LWtoNzI1dTFpZWdzNHN1bnFhOThhcHUxMHU4djhhcmFmLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJhcmp1bkBsaW5rd2FyZS5pbiIsImF0X2hhc2giOiJQVnJxTURpNDViZnVGTm9kTmlsSFlRIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjE2OTc2NjIyODk2OC1raDcyNXUxaWVnczRzdW5xYTk4YXB1MTB1OHY4YXJhZi5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImhkIjoibGlua3dhcmUuaW4iLCJpYXQiOjE0Mzc0ODIwNTUsImV4cCI6MTQzNzQ4NTY1NX0.uSMrV8rOz4T4i5MhiCeQueNVGLv4NBLP-gtOcyow8t4BY9qvUO78sG4y0jPhbclPdX1kUZjzMVTeah2nU9fTYyl50dlj5FzWNy7LyM-a1GC2jEwkgWMgHdRPh6l7dqMrjQ9sU1rF-ZaiWfG7C9VJTJ76uEWRiSKKA9EFQtBil3xBtmDH07UMRxkbri2jBwaCPAWgjU8-dTarrxNESrwrO_nptaRzfGeaTyQBIYCAk6_9deXmblPgteER1OHoa65xb1OVK3ZPeZ3_dj9gjlXSyGp2ho5WIFGf2xRvW4XoROpUYqhLvrS3s-YrrZ8J5X5-3mafrs1qDjJYJogctbW7dg)
will give you the metadata.
while decoding the data ,it will give the result as
{"iss":"accounts.google.com","sub":"114218410824735892084","azp":"169766228968-kh725u1iegs4sunqa98apu10u8v8araf.apps.googleusercontent.com","email":"arjun#linkware.in","at_hash":"PVrqMDi45bfuFNodNilHYQ","email_verified":true,"aud":"169766228968-kh725u1iegs4sunqa98apu10u8v8araf.apps.googleusercontent.com","hd":"linkware.in","iat":1437482055,"exp":1437485655}
Above result you can find the email filed. I hope this will help you.
I have an API GET Request that runs multiple times using a for loop. I am successfully able to create some NSStrings from this, but given that the loop, I need a good way to store it all together. So, at the end of the connectionRequest, I have it run another method, where I add the NSString to an NSMutableArray. However, when I check the contents of the NSMutableArray, it's only the most recent NSString in there. What am I missing?
- (void)viewWillAppear:(BOOL)animated {
for(int i = 0; i< self.theNumber; i++) {
[self getQuote];
}
}
-(void) getQuote {
NSString *bringitalltogether = #"URLOFAPI";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:bringitalltogether]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
[request setHTTPMethod:#"GET"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSMutableDictionary *allResults = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:nil];
NSArray *book = [allResults valueForKey:#"bookname"];
self.bookstring = [book objectAtIndex:0];
NSArray *chapter = [allResults valueForKey:#"chapter"];
self.chapterstring = [chapter objectAtIndex:0];
NSArray *verse = [allResults valueForKey:#"verse"];
self.versestring = [verse objectAtIndex:0];
NSArray *text = [allResults valueForKey:#"text"];
self.textstring = [text objectAtIndex:0];
[self doneGotIt];
}
- (void) doneGotIt {
self.theArray = [[NSMutableArray alloc] init];
NSString *doIt = [NSString stringWithFormat:#"%# - %# %#:%#", self.textstring, self.bookstring, self.chapterstring, self.versestring];
[self.theArray addObject:doIt];
NSLog(#"%#", self.theArray);
}
The console shows the NSLog running the appropriate number of times, but each time, the array stays with just one verse, when I would expect it to gradually grow.
You are creating the new array instance every time. thats y , u are getting the last part.
- (void) doneGotIt {
//Create array only once if not yet created in memory
if (!self.theArray) {
self.theArray = [[NSMutableArray alloc] init];
}
NSString *doIt = [NSString stringWithFormat:#"%# - %# %#:%#", self.textstring, self.bookstring, self.chapterstring, self.versestring];
[self.theArray addObject:doIt];
NSLog(#"%#", self.theArray);
}
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.
I'm experiencing a problem with my code but I'm not sure why it's doing this. It's just giving me an error saying JSON Error. The UITableView never gets filled with anything. I'm not very experienced with iOS, so any help is appreciated.
//
// ViewController.m
// Westmount Procrastinator
//
// Created by Saleem on 10/25/13.
// Copyright (c) 2013 Saleem Al-Zanoon. All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UIWebView *webView;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *fullURL = #"********";
NSURL *url2 = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url2];
[_webView loadRequest:requestObj];
self.title = #"News";
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:#"****************"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self]; // NSString * urlString = [NSString stringWithFormat:#"http://salespharma.net/westmount/get_all_products.php"];
// NSURL * url = [NSURL URLWithString:urlString];
// NSData * data = [NSData dataWithContentsOfURL:url];
// NSError * error;
// NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// NSLog(#"%#",json);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
data = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{
[data appendData:theData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSArray *responseDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:NULL];
//news = [responseDict objectAtIndex:0];
// [mainTableView reloadData];
if ([responseDict isKindOfClass:[NSArray class]]) {
news = responseDict;
[mainTableView reloadData];
} else {
// Looks like here is some part of the problem but I don't know why.
NSLog(#"JSON Error.");
UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Could not contact server!" delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"The download could not complete - please make sure you're connected to either 3G or Wi-Fi." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [news count];
}
NSString *_getString(id obj)
{
return [obj isKindOfClass:[NSString class]] ? obj : nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
cell.textLabel.text = _getString([[news objectAtIndex:indexPath.row] objectForKey:#"Issue"]);
cell.detailTextLabel.text = _getString([[news objectAtIndex:indexPath.row] objectForKey:#"Name"]);
return cell;
}
#end
How the JSON looks on the internet:
{
"Issues":[
{
"Issue":"2",
"Link":"google.com",
"Name":"Ios Test"
},
{
"Issue":"3",
"Link":"Yahoo",
"Name":"iOS test 2"
}
],
"success":1
}
Edit: sorry for not being clear in my question, The app does not crash but fails to load the data into the database in the log it puts this up:
2013-10-26 10:26:41.670 Westmount Procrastinator[2490:70b] JSON Error.
2013-10-26 10:26:41.671 Westmount Procrastinator[2490:70b] Server Data:
{"Issues":[{"Issue":"2","Link":"google.com","Name":"Ios Test"}],"success":1}
The goal of the application to contact a database download a list of Issues of a newspaper then list them in the list view.. Then allowing the user to click on the issues and download them.
Edit I added more to the JSON to help explain.
From your sample JSON structure it does not appear to be a NSArray. It is NSDictionary instead. So, while you are parsing JSON data save it in NSDictionary and not in NSArray. Also, change your IF condition afterwards.
Importantly, if your tableview is reading data from an NSArray of NSDictionaries then I would say put this NSDictionary into an NSArray and pass it to table view. Also, check from server side what is the output in case they are multiple dictionaries in which you need to handle accordingly. So essentially there are couple of more lines you need to induce here or else ask data provider (server side) to send NSArray in all cases.
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:NULL];
if ([responseDict isKindOfClass:[NSDictionary class]]) {
NSArray *tableArray = [NSArray arrayWithArray:responseDict[#"Issues"]];
}
Now use tableArray to populate your table.
Issues is an array of dictionaries, so you should ask for the dictionary at the indexpath.row, then use objectForKey to pull the appropriate value from that dictionary.
NSDictionary *myDict = #{#"Issues": #[#{#"Issue": #"2",
#"Link": #"google.com",
#"Name": #"Ios Test"},
#{#"Issue": #"3",
#"Link": #"Yahoo",
#"Name": #"iOS test 2"}],
#"success": #"1"};
NSArray *issues = [myDict objectForKey:#"Issues"];
[issues enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Issue: %# Link: %# Name: %#", [obj objectForKey:#"Issue"], [obj objectForKey:#"Link"], [obj objectForKey:#"Name"]);
}];
Will return:
2013-10-26 16:42:43.572 Jsontest[43803:303] Issue: 2 Link: google.com Name: Ios Test
2013-10-26 16:42:43.573 Jsontest[43803:303] Issue: 3 Link: Yahoo Name: iOS test 2