Xcode - Write and Delete to Plist - objective-c

I have a plist with two arrays that looks like this:
I currently load the plist like this:
// Find path of plist
NSString *path = [[NSBundle mainBundle] pathForResource:#"nameofPList" ofType:#"plist"];
// Read the data into arrays
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
NSMutableArray *tableData = [dict objectForKey:#"array2"];
How do I write new items to the "array2" array in the plist (code, not manually)
How do I delete items from "array2"? (code, not manually)
Thank you.

You probably want:
NSMutableArray *tableData = [dict[#"array2"] mutableCopy];
^^^^^^^^^^^
(otherwise you'll get an immutable array).
Add items with:
[tableData addObject:#"new item"];
Delete with:
[tableData removeObjectAtIndex:someIndex];
or:
[tableData removeObject:someObject];
and anything else you can find in the NSMutableArray Class Reference.
However "write back" sounds like you are attempting to write the .plist back into the app bundle. While this will work in the iOS Simulator, it will fail on a real devices.
You cannot write to the app bundle at runtime; write to the Documents folder instead and be flexible about where to read from.

Related

Objective c save to my plist

I have the plist file under the resources folder which is name is logical-app.plist
In ios8 if you want Gps will work then NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription keys should be added into the Info.plist
I want to add NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription keys in code in my appdelegate class.
Im trying to add the following code for solving this issue:
//write
filePath = #"/System/Library/CoreServices/SystemVersion.plist";
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:#"1.1.1" forKey:#"NSLocationWhenInUseUsageDescription"];
[plistDict writeToFile:filePath atomically: YES];
//endwrite
//read plist
filePath = #"/System/Library/CoreServices/SystemVersion.plist";
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
value = [plistDict objectForKey:#"NSLocationWhenInUseUsageDescription"];
im trying to get
filePath = [[NSBundle mainBundle] pathForResource:#"ClickMobileCDV-Info" ofType:#"plist"];
and it is nil too....
But with no success.... when i read it from the plist it was nil...
How can i solve this issue?
You've completely got the wrong end of the stick. In order to add NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription, you edit the app's plist file within Xcode and it's included in the app bundle.
There is no code needed to read/write system .plist files at runtime (the writing of which would fail anyway, due to permission errors).

plist wont pull into my NSMutableArray. am i missing something?

So here's my code. I'm trying to display content from a plist into a table and i keep running into errors. ive been at it all day so i'm probably missing something fairly easy. hope you guys can figure out why when i build, the table is empty.
here is my plist (without headers):
<array>
<dict>
<key>word</key>
<string>AWord1</string>
<key>definition</key>
<string>here is a definition</string>
<key>partOfSpeech</key>
<string>here is a part of speech</string>
</dict>
<dict>
<key>word</key>
<string>Bword1</string>
<key>definition</key>
<string>here is a definition</string>
<key>partOfSpeech</key>
<string>here is a part of speech</string>
</dict>
</array>
</plist>
edit: closing tags were missing due to misformatting - fixed
ok. here is my new code. i NSLog'd and decided to back up to before i went to plist. so, if you could help. how would you suggest i pull this data from plist instead (assuming the data is in the plist)
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
NSArray *countriesToLiveInArray = [NSArray arrayWithObjects:#"Iceland", #"Greenland", #"Switzerland", #"Norway", #"New Zealand", #"Greece", #"Italy", #"Ireland", nil];
NSDictionary *countriesToLiveInDict = [NSDictionary dictionaryWithObject:countriesToLiveInArray forKey:#"Countries"];
NSArray *countriesLivedInArray = [NSArray arrayWithObjects:#"India", #"U.S.A", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", nil];
NSDictionary *countriesLivedInDict = [NSDictionary dictionaryWithObject:countriesLivedInArray forKey:#"Countries"];
[listOfItems addObject:countriesToLiveInDict];
[listOfItems addObject:countriesLivedInDict];
//Initialize the copy array.
copyListOfItems = [[NSMutableArray alloc] init];
//Set the title
self.navigationItem.title = #"Countries";
//Add the search bar
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
searching = NO;
letUserSelectRow = YES;
i feel as though i'm still not actually telling it to parse the data from the plist. i've only init'd it. thoughts?
Your code seems very incomplete, it doesn't bear much relation to the plist. Here are a few issues
as noted by H2CO3 and Fogmeister, the plist as you show it is missing a closing </array> tag (but lets assume that is a typo in the question)
you load the entire array into a single entry in a countriesToLiveIn dictionary (against the key "definition")
countriesToLiveIn becomes a single object in the array listOfItems
you initialise a copyOfListItems array but then don't do anything with it
Then you do not indicate where the table is getting it's date from.
If it is from copyOfListItems, well that array is empty .: empty table.
If it is from listOfItems you will be parsing the countriesToLiveIn dictionary somehow, but you don't show how.
If it is directly from the plist array countriesToLiveInArray then that missing </array> tag could be a clue. You would also need to be parsing the array's contained dictionaries somehow, and you don't show us that code, there could be something wrong there.
To get further with this I suggest copious use of NSLog to find out how far the data gets in to your objects. Perhaps you could expand your question with the results if you are still getting stuck.
update
Following your updated code, my first suspicion is that there was a problem with your URL.
in your previous edit this is the suspect line
NSMutableArray *wordListArray = [[NSMutableArray alloc] initWithContentsOfURL: [NSURL URLWithString:#"http://url.com/dictpPlist.plist"]];
You need to NSLog right after it:
NSLog (#"wordListArray %#", wordListArray);
To confirm that you are not picking up the plist here. At least then we isolate the problem to this point in your code.
Then we need to question the URL - is it correct? how did the plist get there? can you verify it independently? Is it a local file URL or a network URL?
If you are accessing a network resource, this is quite likely your problem. The initWithContentsOfURL methods should only really be used with local filesystem URLs. See for example
initwithcontentsofurl methods considered harmful.
You should be using NSURLConnection asynchronously instead. Apple is a little cagey about this also:
aURL: The location of a file containing a string representation of an array produced by the writeToURL:atomically: method.
Assuming this is your issue, why don't you get it working with a local filesystem plist first.
Write one in code from your listOfItems array:
- (void) createPlist
{
NSFileManager* fManager = [NSFileManager defaultManager];
NSError* error;
NSURL* docsURL = [fManager URLForDirectory:NSDocumentDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:NO
error:&error];
NSURL* plistURL = [docsURL URLByAppendingPathComponent:#"testlist.plist"];
[listOfItems writeToURL:plistURL atomically:YES];
}
Read it back in, verify it works, then sort out how to do the same over a network.
try below code
// Path to the plist (in the application bundle)
NSString *path = [[NSBundle mainBundle] pathForResource:
#"dictpPlist" ofType:#"plist"];
// Build the array from the plist
NSMutableArray *array2 = [[NSMutableArray alloc] initWithContentsOfFile:path];
// Show the string values
for (NSString *str in array2)
NSLog(#"--%#", str);

Create plist first in Xcode?

I've read conflicting views on this
http://ipgames.wordpress.com/tutorials/writeread-data-to-plist-file/
If I want to use a plist to hold my tile map objects game data, do I have to create a plist with xcode first? and then update that? or do I not need to do that and I can just create it from scratch with code when the game runs?
If I don't have to create one with xcode first, what would be the benefit of doing that?
The code from your link is useful if you want some default data in the property list when the application is started for the first time.
If you don't need default data, don't have to create a property list in Xcode and include it in your application.
NSString *path = ... // path to plist file in Documents directory
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
if (plistDict == nil) {
// No plist present (or invalid contents), start with empty dictionary:
plistDict = [[NSMutableDictionary alloc] init];
}
Now you can add/modify/remove items in plistDict and save it later.

Reading strings from txt files into NSArrays in iOS

After much reading it seems that, really, the only way to read a number of lines from a text file into an NSArray is with this:
NSString *myfilePath = [[NSBundle mainBundle] pathForResource:#"poem" ofType:#"txt"];
NSString *linesFromFile = [[NSString alloc] initWithContentsOfFile:myfilePath encoding:NSUTF8StringEncoding error:nil];
myArrayOfLines = [NSArray alloc];
myArrayOfLines = [linesFromFile componentsSeparatedByString:#"\n"];
NSArrays have a method for initWithContentsOfFile but I have not seen any examples of how to use this. I have read some posts that state that the file must be a plist and not a generic txt file.
Is this really the case? Is there a way to read lines (terminated with \n) directly into an NSArray?
You have it right, except the line myArrayOfLines = [NSArray alloc]; which is useless.
Don't bother with plist if you already have a good txt file.
But for curiosity, here is a link which explains how it works with plist files : link
Also, if you don't use ARC, you'll have some leaks, but that's another question, and we don't have the whole code, so I might be wrong.

How to save apps data Xcode

I have been searching for many days on how to save my apps data. I found some stuff but it was very complicated and badly explained. I need that when I completely close my apps all the data I entered in the text field are still there when I open my apps again. I tried a tutorial but this only let me save about 8 textfields and I need to save thousands I am starting Objective-C and Xcode so if somebody want to give me an answer please make it very precise.
Alright, what I'd suggest would be putting all the data from your text fields into an array and saving that to a file, then loading it when you re-open the app.
The first thing you need is a save file. This function will create one for you.
-(NSString*) saveFilePath{
NSString* path = [NSString stringWithFormat:#"%#%#",
[[NSBundle mainBundle] resourcePath],
#"myfilename.plist"];
return path;}
Now that that's done you need to create your saving array. Hopefully you have your thousands of textfields already fitted into an array of some sort. If not, this will be a painful process regardless of how you tackle it. But anyway... (Here, labelArray will be the array of all your text fields/labels/etc.)
NSMutableArray* myArray = [[NSMutableArray alloc]init];
int i = 0;
while(i < labelArray.count){
[myArray addObject: [labelArray objectAtIndex: i].text];
i ++;
}
[myArray writeToFile:[self saveFilePath] atomically:YES];
[myArray release];
And the loading code would be something along the lines of
NSMutableArray* myArray = [[NSMutableArray arrayWithContentsOfFile:[self saveFilePath]]retain];
Then you'd simply load the data back into your array of text fields.
Hope this helps.
It sounds like your application architecture may be unsound if you are planning on saving thousands of text fields' data in the fraction of a second you get while your app is closing. It would probably be better to save these as the user enters the data instead of waiting to save all the data at once.
To get the path you are going to write ( or read from! ) to, you do the following:
NSString *writableDBPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"MyFile.extension"];
And then use a method like "writeToFile:automically:" of NSString or NSDictionary etc. to write to the path.