NSArray to plist to TableView - iphone

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

Related

iOS - plist file, nsuserdefaults or text data file

I am working on a mobile app which needs a lot of data. Simply put, the data will be for multiple languages and consist of all the words possible for that language. The app would start with only the English language and a lot of it's words. Then the user can choose to download more languages and their data.
I am trying to figure out the best way to read/save/update this data. Should I create a plist file with English data to start with and just keep adding more data as user downloads new languages? Or should I save all the data in nsuserdefaults? Or, should I just include a text file with all the data and parse it on the fly?
Suggestions?
ps: i understand that as this is a mobile app, file space and parsing time have to be considered
Please read my answer here: https://stackoverflow.com/a/7215501/832065
As said in that answer, all NSUserDefaults are stored together in one plist.
A plist and NSUserDefaults are basically the same, however NSUserDefaults should ONLY be used for saving preferences and not a big amount of data. So don't use NSUserDefaults!
I would consider saving this in a plist (NSDictionary). Like this you can have all data sorted in that file. Simply set the "words" (NSString I assume) as object, and the language as key.
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
[dict setObject:words forKey:language];
[dict writeToFile:filePath atomically:YES];
same for reading:
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSString *words = [dict objectForKey:language];
EDIT:
If each word is assigned to a number (you can just use NSArray) it doesn't differ much:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
NSArray *words = [NSArray arrayWithObjects:allTheWords,nil];
[dict setObject:words forKey:language];
[dict writeToFile:filePath atomically:YES];
same for reading:
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSArray *words = [dict objectForKey:language];
NSString *word = [words objectAtIndex:numberAssignedToWord];
I hope this helps! :)
I would recommend using either an SQL database directly or Core Data. If you have a lot of data, you don't want to load that data completely into memory all the time. It is also easier to handle updates, changes or additions of data.
But your question is so general, and doesn't tell anything on what you actually want to do with the data, how large the data is in KByte or MByte, it is hard to give any good answer.
Writing a lot of data into a text file, user defaults, plist or something similar, doesn't seem the right choice. Using Core Data would be the default way to do such things on iOS.
I thing the easiest way would be to handle the data in a NSMutableArray and store it within the application using NSUserDefaults.
You can handle your data within a NSMutableArray, like so:
NSMutableArray *yourDataStuff = [[NSMutableArray alloc] init];
[yourDataStuff addObject:#"Your data 1"];
[yourDataStuff addObject:#"Your data 2"];
[yourDataStuff addObject:#"Your data 3, etc.."];
Then you can store it using NSUserDefaults, like so:
[[NSUserDefaults standardUserDefaults] setObject:yourDataStuff forKey:#"myData"];
And read your data, like so:
yourDataStuff = [[NSUserDefaults standardUserDefaults] objectForKey:#"myData"];
I think you cannot save large data in the NSUserDefault , and you maybe can not do IO with plist , i had done this , when you read or save , you must read in the whole .plist , and you may reveive memory warning , or crash. you can use C (fread,fwrite) write the data in a .txt , and you may read and write with data stream.

How To remove a key value from Plist in ios?

I wanted to delete the key value in the Plist. I found answers like to delete the value assigned to it and another is to load a new plist but i need to delete a key value
(assuming this is programming-related)
You can load it into an NSDictionary, remove the key/value pair, then write it back:
NSString *pathToPlist = #"/Users/H2CO3/my.plist";
NSMutableDictionary *plist = [NSMutableDictionary dictionaryWithCOntentsOfFile:pathToPlist];
[plist removeObjectForKey:#"MyKeyIWannaDelete"];
[plist writeToFile:pathToPlist atomically:YES];
As of now this is not possible via coding. If you have these kind of scenario's, go with the database. So that, you can delete, what ever the row you want?
PlistDict is the Dictionary that is loaded in to the plist .By using following code we can remove the key value from the plist.
[plistDict removeObjectForKey:#"Key"];
Dictionary must be a Mutable one(NSMutableDictionary).

Can you append a NSMutableArray to a file?

I am trying to write some data from an NSMutableArray to a plist, while keep the old plists content.
The function writeToFile:atomically: overwrites the old contents with the new, I want to append the objects in the new array to the plist.
How can this be done? Thank you.
How can you check for duplicates while doing this?
You could load the contents of the file into an array, then use addObjectsFromArray: in your MutableArray to load the contents into that, then use the writeToFile feature.
i.e.
NSArray *oldArray = [NSArray arrayWithContentsOfFile:filePath];
[newMutableArray addObjectsFromArray:oldArray];
.....
[newMutableArray writeToFile:filePath atomically:YES];
Just create use an instance of NSFileHandle and use -seekToEndOfFile, then do your writing from the array.

Saving Array to PList from downloaded content in table view on iPhone

I copied these posts from a forum where I posted recently, but got no reply.
I have the base for my code all setup, it is a drill down table with navigation controller which loads data into a nsmutabledictionary from a plist with some empty values, on purpose. On command the app then downloads information which is then set, setValue, in NSMutableArray. The issue is that this NSMutableArray is 3 levels down from the root of the plist. I am looking for a way to replace the array in the plist which is loaded and saved in the appdelegate. How do I this? Help is much appreciated.
So that probably didn't make much sense. In the AppDelegate it loads a plist file into an NSMutableDictionary. The plist is like this:
Root
>Title(String)
>Rows(Array)
>>Item 1(Dictionary)
>>>Title(String)
>>>ID(String)
>>>ItemList(Array)
>>>>Item 1(Dictionary)
>>>>>Title(String)
>>>>>ID(String)
>>>>>Value(String)-----------Empty Value which is Downloaded
>>>>Item 2(Dictionary)
>>>>Item 3(Dictionary)
>>>>Item 4(Dictionary)
>>Item 2(Array)
>>Item 3(Array)
>>Item 4(Array)
The Rows array is sent to the RootViewController. When one of these items is selected from the TableView and new instance is created with the table data source set to the ItemList of that selected item. When the user presses a button it downloads the values and using [setValue: forKey:#"Value"] the values are set in the array. Here is where it gets lost. I need to now set this ItemList array back into the main Root dictionary and then that Root dictionary sent back to the AppDelegate, so that on applicationWillTerminate [self.data writeToFile:] can be called and the downloaded information does not need to be downloaded the next time.
I'm not totally sure I understanad what your problem is. Once you've got the new value populated into the array, you just need to use setObject:forKey: on the dictionary to replace the old array.
If you're having trouble getting a reference to the app delegate, you can use [[UIApplication sharedApplication] delegate]
if the problem is that your dictionaries and arrays are nested such that you need to change more than one object to set the value, consider using mutableCopy to produce mutable arrays and dictionaries from the plist on load. Alternatively, maybe think about using a mire-sophisticated data representation, rather than reading and writing plist format.
I believe I might have to use forKeyPath

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.