Adding multiple values as a single entry into an NSMutableArray and retrieving it - iphone

I retrieve 6 values(say name, age, sex, address, id, tag) from a web service. All are string variables. I concatenate these strings and add it to an NSMutableArray. I pass this array to another class, where I need each of these strings separately. That is I need to be able to retrieve these values from the array separately. How can I do this.
Do I need to add tags like "Name", "Age" etc along with the values to make the retrieval easier. Whats the appropriate way to do it.
Edit: i concatenate it into a single string. How should I be adding my values to the collection, so that I can retrieve the elements easily.

IMO, the most appropriate way of doing what you are trying to do is using an NSMutableDictionary, that allows you to access individual elements based on their key.
Example:
loadedBuffers = [[NSMutableDictionary alloc] initWithCapacity:CD_BUFFERS_START];
[loadedBuffers setObject:bufferId forKey:filePath];
...
[loadedBuffers objectForKey:filePath]
You do no strictly need using a dictionary, but it will make your life so much easier.
In your case (if I understand it correctly), I would do:
NSMutableArray* result = [NSArray arrayWithCapacity:kNUM_OF_ROWS];
NSString *name, *age, *sex....;
<for each set of strings from the web service>
<retrieve strings>
NSMutableDictionary dict = [NSMutableDictionary dictionaryWithCapacity:kNUM_OF_FIELDS];
[dict setObject:name forKey:#"name"];
...
[dict setObject:address forKey:#"address"];
[result addObject:dict];
<end_for>
return result;
By doing like this, you will be able to access sequentially each set of strings; then access each string individually.
In short, instead of encoding your set of strings by concatenating them into another string, you would expand them in a dictionary to make retrieval easier.

I would agree that the best practise here would be to use a dictionary or custom object. That way each string gets stored with its companions (e.g. you have one person's data all together) and you don't have to deal with the messy method you already have implemented. It sounds like you might want to save data, so here's a snippet to help you. If that's not what you're after, let me know and I'll modify my response to help!
Say you have a custom object class Person, where you create and manage data objects to save to disk via the app delegate. You'd do something like:
Person *newPerson = [[Person alloc] init];
[newPerson setName:#"John"];
[newPerson setAge:#"25"];
[newPerson setSex:#"M"];
[yourAppDelegate.newPersonArray insertObject:newPerson atIndex:[mainDelegate.newPersonArray count]];

Related

How to save NSDictionaries?

Could you tell me please, how can I make something like this:
For example I have an app which contains info about your pets. But firstly, you should add a pet to a database. In a special view, you enter your pet's name, age, breed, color and etc (keys) and then you save it. Here we are, now you have your first pet in the app. But then you wanna add new pets...
How can I save all these dictionaries with same keys ? You don't know how may dictionaries to create because you don't know how many pets an user wanna add in the app. What is the easiest way?
What if user wants to add like thousands of pets in the app ? I am sure, I shouldn't create thousands of dictionaries in the code for every possible animal. But how do I do that ?
Like dictionary1 for Deisy, dictionary2 for Bruno, dictionary3 for Hamlet and etc.
Here is a rough description of how it could work:
Somewhere you need to define a collection to hold that pets.
NSMutableSet *myPets = [[NSMutableSet alloc] init];
When the user has entered the data and presses the save button, some method is called in your view controller. Within that method you collect the data, like this:
NSDictionary *pet = [NSDictionary dictionaryWithObjectsAndKeys:nameField.text, #"name", breedField.text,#"breed", nil];
[myPets addObject:pet];
At this point the pet has been put into the myPets NSMutableSet and the compiler will release it, so it doesn't exist anymore. The next time the user enters data and presses the button again, a new pet will be created and put into myPets. Don't worry about millions of instances being created, the compiler will take care of it.
If you want to retrieve individual pets afterwards, you can do something like this
for (NSDictionary *aPet in myPets) {
if ([[aPet objectForKey:#"name"] isEqualToString:#"Lassie"]) {
// do what you want to do with Lassie
}
}
You need an NSArray to hold the NSDictionaries.

Loading text from a file

I am making an Iphone drinking card game app.
All the card mean something different and i want the user to be able to press an info button and then show a new screen with information about the current card. How can i make a document to load text from instead of using a bunch og long strings?
Thanks
You could look into plist files - they can be loaded quite easily into the various collection objects and edited with the plist editor in Xcode.
For instance, if you organize your data as a dictionary, the convenience constructor
+ (id)dictionaryWithContentsOfURL:(NSURL *)aURL
from NSDictionary would provide you with as many easily accessible strings as you need.
This method is useful if you consider your strings primarily data as opposed to UI elements.
Update:
As #Alex Nichol suggested, here is how you can do it in practice:
To create a plist file:
In your Xcode project, for instance in the Supporting Files group, select New File > Resource > Property List
You can save the file in en.lproj, to aid in localization
In the Property list editing pane, select Add Row (or just hit return)
Enter a key name (for instance user1) and a value (for instance "Joe")
To read the contents:
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:#"Property List" withExtension:#"plist"];
NSLog(#"URL: %#", plistURL);
NSDictionary *strings = [NSDictionary dictionaryWithContentsOfURL:plistURL];
NSString *user1 = [strings objectForKey:#"user1"];
NSLog(#"User 1: %#", user1);
A plist, a JSON string, and an SQLite database walked into a bar ...
Oops!! I mean those are the three most obvious alternatives. The JSON string is probably the easiest to create and "transport", though it's most practical to load the entire thing into an NSDictionary and/or NSArray, vs read from the file as each string is accessed.
The SQLite DB is the most general, and most speed/storage efficient for a very large number (thousands) of strings, but it takes some effort to set it up.
In my other answer, I suggest the use of a dictionary if your texts are mostly to be considered as data. However, if your strings are UI elements (alert texts, window titles, etc.) you might want to look into strings files and NSBundle's support for them.
Strings files are ideally suited for localization, the format is explained here.
To read them into you app, use something like this:
NSString *text1 = NSLocalizedStringFromTable(#"TEXT1", #"myStringsFile", #"Comment");
If you call your file Localizable.strings, you can even use a simpler form:
NSString *str1 = NSLocalizedString(#"String1", #"Comment on String1");
A useful discussion here - a bit old, but still useful.

How to get object for key from NSDictionary?

In dictionary named dict the key value pair is:
"alba\U2019s window" = "A model in westindies.";
And to send objectForKey: I am getting the string like "alba's window". When I send like following:
[dict objectForKey:alba's window];
I am not getting anything, it is showing null.
For starters, you might want to make that an actual string, like so:
[dict objectForKey:#"alba's window"];
Note also that \U2019 is not '; but ’, which is a different character entirely.
And more generally, sticking to [a-zA-Z0-9]+ for dictionary keys is probably a good idea, unless you are inserting and retrieving programmatically using the exact same string as a key.
Since iOS6 onwards, a convenient method for setting and accessing the object for a key from an NSDictionary is:
//Setting the object in NSMutableDictionary
dictionary[#"someKey"] = #"someString";
//Accessing the object
NSString *str = dictionary[#"someKey"];
Make sure your dict isn't null; sending a message to a null object will silently fail and return null.
Another way to check your key/values is to simply NSLog(#"%#",dict); and this will show you the contents of the dictionary. Note that this output only shows quotes around values when the value contains a space.
Also, make sure you're using the same pairs of strings as the key - it looks like you're using "alba\U2019s window" in addition to "alba's window".

NSArray to plist to TableView

Thanks in advance. I create an array with 6 parts, each an NSString in one of my views. Each string is taken from a UITextField. I want to make a save button that saves the Array into a plist. I then want a TableView to display a table sorted by the first object in the array, the first string.
I've created a blank plist with the name I want and named the plist the same thing as the array. Frankly, I'm lost after that. I don't understand if what I'm making is a dictionary in the plist or an array, and how to do it.
Once the table is made, I think I can handle pushing new views from the selected row.
Anything would help. Thanks and stack overflow has been really helpful.
Thanks again.
If you are really set on using files, to this to write an array to your .plist:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:theArray forKey:yourKey];
[dictionary writeToFile:#"/somepath/blah.plist" atomically:YES];
[dictionary release];
This will set the root of your .plist file to be a NSDictionary.
If you want it to be an NSMutableArray just change the class of the *dictionary.
Answer via: primary source
To store data it's better to use NSUserDefaults and not files because reading and writing it it's much easier.
There is a primer at: Primer link

How do I store a string as an array in a Cocoa property list?

I am trying to save two strings. One string needs to be saved as type ARRAY in the pList and the second string needs to be saved as String in the Array.
I can use the code:
[dictionary setObject:(id)anObject forKey:(id)aKey>]
but it doesn't save it correctly. I can cast one of the strings as an array, but it still doesn't work right.
What is the proper method for saving an array to the pList?
Here is what my pList looks like:
<dict>
<key>Test One</key>
<array>
<string>A13#</string>
</array>
<key>Another Test</key>
<array>
<string>1111111111</string>
</array>
<key>Test Three</key>
<array>
<string>2222222222</string>
</array>
<key>Final Test</key>
<array>
<string>3333333333</string>
</array>
</dict>
here is the method I am using to try to
-(void)writeToFile:(NSString *)s1{
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"saved" ofType:#"plist"];
NSMutableDictionary *dictionary = [[[NSDictionary alloc] initWithContentsOfFile:plistPath] mutableCopy];
NSString *tempString = [NSString stringWithFormat:#"1234567"];
[dictionary setObject:tempString forKey:s1];
[dictionary writeToFile:plistPath atomically:YES];
}
You can't cast or otherwise convert a string into an array; they're separate, distinct objects. It's the same as if in real life you try to turn your dog into a station wagon, it isn't happening.
Instead, put your dog inside the station wagon (or put your string(s) inside an array). You can create the array with [NSArray arrayWithObjects:#"string1", #"string2", nil];. Stick that inside your dictionary for a given key, along with your final string for another key, save it, and you'll have a plist with an array of one or more strings.
Also, in your code example your dictionary is leaking memory. Read up on memory management in Objective-C, you're going to run into lots of crashes and performance issues until you understand it well.
You an convert a string to a single element array with
[NSArray arrayWithObject:str];
So if you want your plist to contain entries as arrays of strings, and you want just a single string as an element, then you do something like:
[dictionary setObject:[NSArray arrayWithObject:tempString] forKey:s1];
I don't actually no why you would want it this way unless you want to allow for multiple strings per key at some other time.
Also, as Marc mentioned, you are leaking the initial (unmutable) dectionary you create. Read the memory management rules at http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html.
Further, you should never write inside your application's bundle. For one thing, your application may be on a write protected volume or the current user may not have permissions to change it. For another, the file would then be shared by all users. And for a third, it would break the code signing. Instead, write the file to either the Preferences folder or the Application Support folder.
And finally, if these are intended to be user preferences of some sort, then you should use the preferences system, which allows configuring defaults and stores the preferences in the preferences folder for you. See http://developer.apple.com/documentation/Cocoa/Conceptual/UserDefaults/UserDefaults.html for more information.
The correct way to save an NSArray (by itself) to a plist file is as follows:
NSArray* anArray = ...;
[anArray writeToFile:#"/path/to/file.plist" atomically:YES];
However, you can't save an NSString as an array. Given the XML plist you provided, if you want to add entries with the same format, you can use this much simpler code:
- (void) writeToFile:(NSString *)string {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"saved" ofType:#"plist"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[dictionary setObject:[NSArray arrayWithObject:#"1234567"] forKey:string];
[dictionary writeToFile:plistPath atomically:YES];
}
This also avoids a memory leak in your code, where the receiver of -mutableCopy escapes with a retain count of 1. (This isn't a problem under GC, but it's still bad practice.) You shouldn't need to use +[NSString stringWithFormat:], just use a string literal. If you want to use a different as the string in the array, you can either pass it in as an additional parameter, grab it from another method, etc.
This method is still brittle in that it only stores one string in the array matched with the given key — also, the method name would be better if it were more indicative of exactly what it does. Also, if there will only ever be one string value for each key, you might consider revising the plist to omit the arrays entirely, since it just chews up space and complicates the code.