Vary number of objects in array - objective-c

In my app the user can create unlimited UITextFields. then I get the information of all of them and upload in a json file:
NSString *object;
NSString *object2;
NSString *object3;
NSString *object4;
NSString *object5;
NSString *size;
for (UITextField *text in array2) {
int touchedtag = text.tag;
NSUInteger tagCount = touchedtag;
switch (tagCount) {
case 1:
object = [NSString stringWithFormat:#"%# %# %#", text.text, NSStringFromCGRect(text.frame), text.font];
break;
case 2:
object2 = [NSString stringWithFormat:#"%# %# %#", text.text, NSStringFromCGRect(text.frame), text.font];
break;
case 3:
object3 = [NSString stringWithFormat:#"%# %# %#", text.text, NSStringFromCGRect(text.frame), text.font];
break;
case 4:
object4 = [NSString stringWithFormat:#"%# %# %#", text.text, NSStringFromCGRect(text.frame), text.font];
break;
case 5:
object5 = [NSString stringWithFormat:#"%# %# %#", text.text, NSStringFromCGRect(text.frame), text.font];
break;
default :
break;
}
}
NSArray *keys = [NSArray arrayWithObjects:#"text", #"text2", #"text3", #"text4", #"text5", nil];
NSArray *objects = [NSArray arrayWithObjects:object,object2,object3, object4, object5, nil];
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSString* jsonString = [jsonDictionary JSONRepresentation];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
[jsonData writeToFile:path atomically:YES];
NSString *destDir = #"/sandbox/";
[[self restClient] uploadFile:filename toPath:destDir
withParentRev:nil fromPath:path];
[[self restClient] loadMetadata:#"/sandbox/"];
}
The problem is that the number of objects is not independent (object, object2...). so if the user creates less than 5 text fields the app crashes, while if more than 5 nothing happens, but the info for tag 6 and on is not recorded. How can I vary the number of objects according to the number of fields created?

Learn how to use NSMutableArray: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html
It allows you to add and remove objects "on the fly", just like using a Vector in many other languages. (Java, ActionScript, C++...)
Example:
(someValue is a previously declared variable)
stuff = [[NSMutableArray alloc] initWithCapacity: someValue];
[stuff insertObject:object1 atIndex:0];
[stuff insertObject:object2 atIndex:1];
[stuff insertObject:object2 atIndex:2];
...
This code is to initialize it with a specific number of objects, which seeems to be what you are looking for. NSMutableArray also allows you to adjust the number of objects in the array at a later time.

Related

NSInvalidArgumentException [NSDictionary initWithObjects:forKeys:]: count of objects (0) differs from count of keys (1)

Got the error NSInvalidArgumentException [NSDictionary initWithObjects:forKeys:]: count of objects (0) differs from count of keys (1). I used following code for
NSString *errorDesc = nil;
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *jsonDictionary = [parser objectWithString:responseData];
paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
documentsPath = [paths objectAtIndex:0];
plistPath = [documentsPath stringByAppendingPathComponent:#"json_keys.plist"];
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:jsonDictionary, nil] forKeys:[NSArray arrayWithObjects: #"json_keys", nil]];
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc];
if (plistData)
{
[plistData writeToFile:plistPath atomically:YES];
}
else
{
NSLog(#"Error in saveData: %#", errorDesc);
[errorDesc release];
}
Judging from error message, [parser objectWithString:responseData] returns nil in this case. So, [NSArray arrayWithObjects:jsonDictionary, nil] creates empty array. After that, you are trying to create NSDictionary, passing empty array as values and array with #"json_keys" string as keys. So, error message is pretty accurate in this case.
Fix for this situation depends on what you are trying to achieve.
You can simply return from your method and don't do anything in case, when jsonDictionary is nil:
// ...
NSDictionary *jsonDictionary = [parser objectWithString:responseData];
if (nil == jsonDictionary) {
return;
}
paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// ...
Another possibility is storing empty plistDict for this case:
NSMutableDictionary *plistDict = [NSMutableDictionary dictionaryWithCapacity:1];
if (nil != jsonDictionary) {
[plistDict setObject:jsonDictionary forKey:#"json_keys"];
}
Of course, you can also find out why [parser objectWithString:responseData] returns nil and fix that.

How can I convert the values is an NSDictionary into an NSString?

I have a method in Objective-c that takes in an NSDictionary and returns the values as a space-separated NSString. This application is cross-platform, and as such I cannot use fast enumeration. This is what I have so far, followed by the output (which shows that the String is never created):
-(NSString *)stringValuesFromDict:(NSDictionary *map)
{
NSArray *values = [map allValues];
NSString *params = [NSString string];
NSLog(#"values length: %d", [values count]);
NSLog(#"values = %#", [values description]);
for (int i = 0; i < [values count]; i++)
{
[params stringByAppendingString:[values objectAtIndex:i]];
[params stringByAppendingString:#" "];
}
NSLog(#"params = %#", params);
return params;
}
The NSDictionary:
{"arg1"="monkey"}
The output:
values length: 1
values = (
monkey
)
params =
What am I doing wrong? How can I get params to be set to monkey?
If I read the question correctly, all you need is
[[dict allValues] componentsJoinedByString:#" "]
You need a mutable string. Change this:
NSString *params = [NSString string];
to this:
NSMutableString *params = [NSMutableString string];
Then change these:
[params stringByAppendingString:[values objectAtIndex:i]];
[params stringByAppendingString:#" "];
to these:
[params appendString:[values objectAtIndex:i]];
[params appendString:#" "];
stringByAppendingString: returns a new string. So you would have to do something like this:
params = [params stringByAppendingString:[values objectAtIndex:i]];
But the disadvantage is, that every time a new string is created, which is wasting memory
You should propably use a NSMutableString instead. And then you can just call
[params appendString:[values objectAtIndex:i]];

Fix unicode characters in NSString

I am getting a string response from the Google Directions API that contains characters that are supposed to represent a different-language character. Similiar to Ƨ³, similiar to these type of characters. I think the characters are portugese, but anyways my string contains like this:
\U00e3o
(I am not sure if those are zeroes or 'O's)
I am not sure what the technical term for these characters are, but how can I fix them in my string so they print properly.
Thank you
UPDATE:
I have updated my question title with the correct term 'unicode'.
I have checked a few questions:
NSString Unicode display
Detect Unicode characters in NSString on iPhone
iOS HTML Unicode to NSString?
And a few others. I have followed the answer, but the unicode characters are not fixed.
UPDATE:
Here is my code to get the response from GDirection.
Forming the request and getting a response:
AFHTTPClient *_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com/"]];
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
[_httpClient setDefaultHeader:#"Accept" value:#"application/json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location.coordinate.latitude, location.coordinate.longitude] forKey:#"origin"];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location2.coordinate.latitude, location2.coordinate.longitude] forKey:#"destination"];
[parameters setObject:#"false" forKey:#"sensor"];
[parameters setObject:#"driving" forKey:#"mode"];
[parameters setObject:#"metric" forKey: #"units"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path: #"maps/api/directions/json" parameters:parameters];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200) {
[self parseResponse:responseObject];
} else {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];
}
Retrieving information from response object:
- (void)parseResponse:(NSDictionary *)response {
NSString *status = [response objectForKey: #"status"];
if (![status isEqualToString: #"OK"]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat: #"Google Directions Response Status: %#", status] delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil, nil];
[alert show];
}
else {
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *routePath = [routes lastObject];
if (routePath) {
NSString *overviewPolyline = [[routePath objectForKey: #"overview_polyline"] objectForKey:#"points"];
legs = [routePath valueForKey: #"legs"];
if (legs) {
/* DIRECTION SET ================================================================================================================================
*/
directionOverview = [[NSMutableDictionary alloc] init];
NSString *legsDis = [NSString stringWithFormat: #"%#", [[legs valueForKey: #"distance"] valueForKey: #"text"]];
NSString *kmDistance = [self cutStringToPreference: legsDis];
if (kmDistance) {
[directionOverview setObject:kmDistance forKey: #"distance"];
milesLabel.text = kmDistance;
milesLabel.font = [UIFont fontWithName:#"interstate" size: 20.0];
}
NSString *durationText = [NSString stringWithFormat: #"%#", [[legs valueForKey: #"duration"] valueForKey: #"text"]];
durationText = [self cutStringToPreference: durationText];
if (durationText) {
[directionOverview setObject:durationText forKey: #"duration"];
}
NSString *startAddress = [NSString stringWithFormat: #"%#", [legs valueForKey: #"start_address"]];
startAddress = [self cutStringToPreference: startAddress];
NSString *endAddress = [NSString stringWithFormat: #"%#", [legs valueForKey: #"end_address"]];
endAddress = [self cutStringToPreference: endAddress];
[directionOverview setObject:startAddress forKey: #"origin"];
[directionOverview setObject:endAddress forKey: #"destination"];
NSArray *steps = [legs valueForKey: #"steps"];
if (steps) {
instructionArray = [[NSMutableArray alloc] init];
durationArray = [[NSMutableArray alloc] init];
distanceArray = [[NSMutableArray alloc] init];
int number = [[[steps lastObject] valueForKey: #"html_instructions"] count];
for (int i = 1; i <= number; ++i) {
NSString *instruction = [[[steps lastObject] valueForKey: #"html_instructions"] objectAtIndex: i-1];
instruction = [self cutStringToPreference: instruction];
instruction = [self flattenHTML: instruction];
instruction = [self stringByDecodingHTMLEntitiesInString: instruction];
[instructionArray addObject: instruction];
NSString *distance = [[[[steps lastObject] valueForKey: #"distance"] objectAtIndex: i-1] valueForKey: #"text"];
[distanceArray addObject: distance];
NSString *duration = [[[[steps lastObject] valueForKey: #"duration"] objectAtIndex: i-1] valueForKey: #"text"];
[durationArray addObject: duration];
}
}
}
_path = [self decodePolyLine:overviewPolyline];
NSInteger numberOfSteps = _path.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [_path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
}
}
Displaying the text in a label:
NSString *overviewAddressText = [NSString stringWithFormat: #"%# to %#", [directionOverview objectForKey: #"origin"], [directionOverview objectForKey: #"destination"]];
overviewAddress.text = overviewAddressText;
UPDATE:
Image of label
So as you can see, in the label, the text contains this kind of substring: S/U00e3o, which is a word that has an unsupported character. How can I fix that so that unicode turns into this: São

JSON representation of NSDictionary

In my app a user can create UITextFields. to each field a tag is added, so that the tags correspond to the cases: 1, 2, 3, 4, ... then I add everything in a NSDictionary, and a json representation:
-(IBAction)buttonDropBoxuploadPressed:(id)sender{
//screenshot
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy_MM_dd"];
NSString *filename = [NSString stringWithFormat:#"By: %# ",
[formatter stringFromDate:[NSDate date]]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#", filename] ];
//[data writeToFile:path atomically:YES];
//NSString *destDir = #"/sandbox/";
// [[self restClient] uploadFile:filename toPath:destDir
// withParentRev:nil fromPath:path];
// [[self restClient] loadMetadata:#"/sandbox/"];
//JSON
NSString *object;
NSString *object2;
NSString *object3;
NSString *object4;
NSString *object5;
NSString *object6;
NSString *object7;
NSString *object8;
NSString *object9;
NSString *object10;
NSString *object11;
NSString *object12;
NSString *object13;
NSString *object14;
NSString *object15;
for (UITextField *text in messagename) {
int touchedtag = text.tag;
NSUInteger tagCount = touchedtag;
switch (tagCount) {
case 1:
object = [NSString stringWithFormat:#"%#", text.text];
break;
case 2:
object2 = [NSString stringWithFormat:#"%#", text.text];
break;
case 3:
object3 = [NSString stringWithFormat:#"%#", text.text];
break;
case 4:
object4 = [NSString stringWithFormat:#" %#", text.text];
break;
case 5:
object5 = [NSString stringWithFormat:#"%#", text.text];
break;
case 6:
object6 = [NSString stringWithFormat:#"%#", text.text];
break;
case 7:
object7 = [NSString stringWithFormat:#"%#", text.text];
break;
case 8:
object8 = [NSString stringWithFormat:#"%#", text.text];
break;
case 9:
object9 = [NSString stringWithFormat:#"%#", text.text];
break;
case 10:
object10 = [NSString stringWithFormat:#"%#", text.text];
break;
case 11:
object11 = [NSString stringWithFormat:#"%#", text.text];
break;
case 12:
object12 = [NSString stringWithFormat:#"%#", text.text];
break;
case 13:
object13 = [NSString stringWithFormat:#"%#", text.text];
break;
case 14:
object14 = [NSString stringWithFormat:#"%#", text.text];
break;
case 15:
object15 = [NSString stringWithFormat:#"%#", text.text];
break;
default :
break;
}
}
//arrays
NSString * objects[] = { object, object2, object3, object4, object5, object6, object7, object8, object9, object10, object11, object12, object13, object14, object15};
NSMutableArray *textnameobject = [[NSMutableArray alloc] initWithCapacity:b];
textnameobject = [NSMutableArray arrayWithObjects:objects count:b];
NSMutableArray *textnamekeys = [[NSMutableArray alloc] initWithCapacity:b];
NSString * textnumber[] = {#"title", #"title", #"title",#"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title"};
textnamekeys = [NSMutableArray arrayWithObjects:textnumber count:b];
//arrays
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObject: textnameobject forKey:textnamekeys];
/*
NSArray *objects2 = [NSArray arrayWithObjects:jsonDictionary, nil];
NSArray *keys2 = [NSArray arrayWithObjects:allkeys, nil];
NSDictionary *mainDict = [NSDictionary dictionaryWithObjects:objects2 forKeys:keys2];
*/
NSString* jsonString = [jsonDictionary JSONRepresentation];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
[jsonData writeToFile:path atomically:YES];
NSString *destDir = #"/sandbox/";
[[self restClient] uploadFile:filename toPath:destDir
withParentRev:nil fromPath:path];
[[self restClient] loadMetadata:#"/sandbox/"];
//JSON
}
When I press the button I get the following error:
JSONRepresentation failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=1 \"JSON object key must be string\" UserInfo=0x2e8370 {NSLocalizedDescription=JSON object key must be string}"
)
and consequentially a dropbox error. this worked on my previous app and the code is exactly the same. the json library is added correctly. I can't understand!! Please help!
Your code, rewritten.
- (IBAction)buttonDropBoxUploadPressed: (id)sender
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat: #"yyyy_MM_dd"];
NSString *filename = [NSString stringWithFormat: #"By: %# ", [formatter stringFromDate: [NSDate date]]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex: 0];
NSString *path = [documentsDirectory stringByAppendingPathComponent: filename];
NSMutableDictionary *titles = [NSMutableDictionary dictionary];
for (UITextField *textField in messagename)
{
[titles setObject: textField.text forKey: #"title"];
// as you can see, here you're replacing the value # at key "title" with a new object on every pass
}
NSString *jsonString = [titles JSONRepresentation];
NSData *jsonData = [jsonString dataUsingEncoding: NSUTF8StringEncoding];
[jsonData writeToFile: path atomically: YES];
NSString *destDir = #"/sandbox/";
[[self restClient] uploadFile: filename toPath: destDir withParentRev: nil fromPath: path];
[[self restClient] loadMetadata: #"/sandbox/"];
}
However, regarding my comment, you're not actually serializing your text fields' text into anything usable. At the end of this, at best, you'll have something that looks like this:
{
"title": "My Text Field Value"
}
Though I'm also relatively certain that one or more of your text fields' text is nil, which is causing your JSON problem.

Parse JSON in Objective-C with SBJSON

I just want to parse this JSON string in Objective-C using the SBJSON framework, and retrieve the three units of data:
{"x":"197","y":"191","text":"this is a string"}
How can this be done?
NSString * jsonString = #"{\"x\":\"197\",\"y\":\"191\",\"text\":\"this is a string\"}";
SBJSON *jsonParser = [[SBJSON alloc] init];
NSDictionary * dictionary = [jsonParser objectWithString:jsonString];
NSLog(#"x is %#",[dictionary objectForKey:#"x"]);
[jsonParser release];
Here's an example:
NSString *jsonText = #"...";
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *dict = [parser objectWithString:jsonText];
for (NSString *key in [#"x y text" componentsSeparatedByString:#" "]) {
NSLog(#"%# => %#", key, [dict objectForKey]);
}
Here's something similar for SBJson4Parser:
id parser = [SBJson4Parser parserWithBlock:^(id v, BOOL *stop) {
for (NSString *key in [#"x y text" componentsSeparatedByString:#" "]) {
NSLog(#"%# => %#", key, [v objectForKey]);
}
}
allowMultiRoot:NO
unwrapRootArray:NO
errorHandler:^(NSError *err) {
// handle error here
}];
NSString *jsonText = #"...";
[parser parse: [jsonText UTF8String]];