Objective-C write array to .plist - objective-c

I have pre-filled information except one string, which will be input by the user. I currently am able to read only a single key with this code:
#define defaultValue #"Someone"
#define myKey #"Event"
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *val = [defaults stringForKey:myKey];
if (val == nil) val = defaultValue;
[myTextField setStringValue:val];
I write it with this code:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *val;
// Get the new value from the textfield
val = [myTextField stringValue];
if ([val isEqualToString:defaultValue]) {
[defaults removeObjectForKey:myKey];
} else {
[defaults setObject:val forKey:myKey];
}
What I really need is to write an array to a .plist like this, and have the 5th string able to be a user input string. How can I do this?:
<plist version="1.0">
<dict>
<key>Event/key>
<dict>
<key>Staff Meeting</key>
<string>Friday Feb 3rd, 2012 </string>
<key>Contact</key>
<string>events#whitehouse.gov</string>
<key>URL</key>
<string>http://www.whitehouse.gov</string>
<key>Status</key>
<string>ATTENDING</string>
<key>Name</key>
<string>Mr. President</string> <------- USER TEXT INPUT
<key>Signature</key>
<data>
20001
</data>
</dict>
</dict>
</plist>

Here an example to create the structure you want.
-(void)saveData:(NSString*)someParam
{
NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:1];
NSDictionary *innerDict;
NSString *staffMeetingValue;
NSString *contactValue;
NSString *nameValue;
staffMeetingValue = #"Friday Feb 3rd, 2012";
contactValue = #"events#whitehouse.gov";
nameValue = someParam;
innerDict = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: staffMeetingValue, contactValue, nameValue, nil]
forKeys:[NSArray arrayWithObjects:#"Staff Meeting", #"Contact", #"Name"]];
[rootObj setObject:innerDict forKey:#"Event"];
id plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj
format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
}
For other info see Creating Property Lists Programmatically
Hope it helps.
P.S. You have to add keys and objects for other tags. I skipped them for the sake of simplicity.
Edit:
This is a simple example how to do that. staffMeetingValue and contactValue values are hardcoded but you can pass it as parameters as nameValue.
-(void)saveDataWithName:(NSString*)nameValue staffMeting:(NSString*)staffMetingValue contact:(NSString*)contactValue {
// previous stuff here
}

Related

Get details from plist file with objective-c

Here is my problem.
I can't seem to figure out how to access the "Details" key in the same level as the "Name" key once search for a specific name key. Maybe I'm missing something?
I know you can get "Details" via [dict objectForKey:#"Details"] but I'm not sure how to get the one on the same levels as the one that was searched for.
Code:
- (IBAction)ScoringButtonView:(id)sender {
ScoringViewController *svController = [[ScoringViewController alloc] initWithNibName:#"ScoringView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:svController animated:YES];
UIButton *scoringButton = (UIButton*)sender;
NSLog(#"Scoring is %# ", scoringButton.currentTitle);
svController.ScoringName = scoringButton.currentTitle;
NSString *path = [[NSBundle mainBundle] pathForResource:#"Scoring" ofType:#"plist"];
NSArray *plistData = [NSArray arrayWithContentsOfFile:path];
for (NSDictionary *dict in plistData) {
if ([[dict objectForKey:#"Name"] isEqualToString:scoringButton.currentTitle]) {
NSLog(#"Scoring == %# ", scoringButton.currentTitle);
// svController.ScoringInfo =
}
}
plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Name</key>
<string>Standard</string>
<key>Details</key>
<string>dagsdfgds</string>
</dict>
<dict>
<key>Name</key>
<string>Advanced</string>
<key>Details</key>
<string>gfdsgdfsgdsfg</string>
</dict>
</array>
</plist>
I'm not sure what the confusion is. You already know how to get the value for the Name key. Getting the value for the Details key is the same:
for (NSDictionary *dict in plistData) {
if ([dict[#"Name"] isEqualToString:scoringButton.currentTitle]) {
NSString *details = dict[#"Details"];
}
}
Note how I used modern Objective-C syntax instead of the old style use of objectForKey:.
//This method should work fine
//Enumeration method is better than for loop
NSString *filePath = [[NSBundle mainBundle] pathForResource:#“LanguageList” ofType:#"json"];
NSString *myJSON = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSJSONReadingAllowFragments error:NULL];
NSError *error = nil;
NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:[myJSON dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
[dict[#"result"] enumerateObjectsUsingBlock:^(id _Nonnull objList, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(#“Values %#”,obj);
*stop = YES;
}
}];

NSUserDefaults does not pick up setting

I am quite new to coding in Objective C and using the settings bundle but here is what I coded.
// Set the application defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"YES"
forKey:#"gameSave"];
[defaults registerDefaults:appDefaults];
[defaults synchronize];
// Get user preference
gameSave = [defaults boolForKey:#"saveGame"];
NSLog(#"Save Game = %#", gameSave ? #"YES" : #"NO");
This is my settings bundle:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Title</key>
<string>XXXXXXXXXXXXX</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>FooterText</key>
<string>www.xxxxxxxxxxxx.com</string>
</dict>
<dict>
<key>DefaultValue</key>
<true/>
<key>Key</key>
<string>gameSave</string>
<key>Title</key>
<string>Save Game</string>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
When tested the gameSave value is NO or false. Can someone point me to a solution? Thanks.
#"YES" is a NSString, not a NSNumber containing a boolean.
You want #YES instead:
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#YES
forKey:#"gameSave"];
Or the same, shorter:
NSDictionary *appDefaults = #{#"gameSave": #YES};
Edit: what if you do... this?
// Set the application defaults -- only if not written yet
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"gameSave"] == nil)
{
[defaults setBool:YES forKey:#"gameSave"];
[defaults synchronize];
}
// Get user preference
gameSave = [defaults boolForKey:#"gameSave"];
NSLog(#"Save Game = %#", gameSave ? #"YES" : #"NO");
This should be straight forward:
To save the bool:
// Write the value to NSUserDefault
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:YES forKey:#"gameIsSaved"];
[defaults synchronize];
To retrieve the boolean value
//Read the value from NSUserDefault
bool gameIsSaved = [defaults boolForKey:#"gameIsSaved"];
NSLog(#"gameIsSaved = %#", gameIsSaved ? #"YES" : #"NO");

nsarray from plist can't return key values

I am using the following code to iterate through a plist to find a string
i then want to use the values for the keys - fraction and number
unfortunately something isn't working and i can't figure it out
any help will be appreciated
NSString *theNumber = #"0.0075";
BOOL found = NO;
NSUInteger f;
for (f = 0; f < [selectorKeysFractions count]; f++) {
NSString * stringFromArray = [selectorKeysFractions objectAtIndex:f];
if ([theNumber isEqualToString:stringFromArray]) {
found = YES;
break;
}
}
if ( found ) {
// do found
//this line fails with unrecognised selector message
NSLog(#"%#",[[selectorKeysFractions objectAtIndex:f]objectForKey:#"fraction"]);
} else {
// do not found
}
my plist data looks like this
<plist version="1.0">
<dict>
<key>fraction</key>
<string>1/128</string>
<key>number</key>
<string>23.78</string>
</dict>
<dict>
<key>fraction</key>
<string>1/234</string>
<key>number</key>
<string>25</string>
</dict>
</plist>
i am setting up the array like this
NSString *path2 = [[NSBundle mainBundle] pathForResource:#"Fractions" ofType:#"plist"];
pickerData2 =[[NSDictionary alloc]initWithContentsOfFile:path2];
selectorKeysFractions = [[NSArray alloc] initWithArray:[pickerData2 allKeys]];
i am doing something wrong but can't figure it out
please help
thanks
You send the message "objectForKey" to an object of NSString. You have to request your NSDictionary to get the right entry.
Check this:
NSLog(#"%#",[pickerData2 objectForKey:[selectorKeysFractions objectAtIndex:f]]);
This should return your string.

Reading plist file

I created plist with big base of different animals in it (keys) and added this plist in my project.
Type of every animal is NSDictionary. In every dictionary there are 5 more keys - characteristics of these animals (). I would like to go through every animal and if I match a certain characteristics of this animal, I put this animal in another array.
So, I tried to make a code:
NSArray *newArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"animals" ofType:#"plist"]];
for (int i = 0;[newArray objectAtIndex:i];i++)
{
if ([[newArray objectAtIndex:i]objectForKey:#"minAge"] == [NSNumber numberWithInt:3])
{
[array addObject:[[newArray objectAtIndex:i]objectForKey:#"name"]];
}
}
So objectAtIndex:i is an animal and minAge is one of it's characteristics. But my code does not work.
I do it for the first time, so what I have done wrong ? Thanks!
UPDATE:
Thank you, your plist works normally ! But I still cant understand why doesn't work mine plist:
Anyway, thank you so much ! I didn't eat and sleep while I was solving this problem :)
You helped me a lot !
NSArray The Return value will be nil if the file can’t be opened or if the contents of the file can’t be parsed into an array.
I suspect the issue is you need to put the contents in a NSDictionary rather than a NSArray
NSDictionary *theDict = [NSDictionary dictionaryWithContentsOfFile:plistFile];
Edit.Further to my answer
NSMutableArray *mutableArray =[[NSMutableArray alloc] initWithObjects:nil];
NSDictionary *mainDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"animals" ofType:#"plist"]];
//--get parent dictionary/Array named animals which holds the animals dictionary items
NSDictionary *parentDictionary = [mainDictionary objectForKey:#"animals"];
//---enumerate through the dictionary objects inside the parentDictionary
NSEnumerator *enumerator = [parentDictionary objectEnumerator];
id value;
while ((value = [enumerator nextObject])) {
if ([[value valueForKey:#"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]])
{
[mutableArray addObject:[value valueForKey:#"name"]];
}
}
If the animal dictionaries are not inside of a parent dictionary or Array, use something like this
NSMutableArray *mutableArray =[[NSMutableArray alloc] initWithObjects:nil];
NSDictionary *mainDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"animals" ofType:#"plist"]];
//---enumerate through the dictionary objects
NSEnumerator *enumerator = [mainDictionary objectEnumerator];
id value;
while ((value = [enumerator nextObject])) {
if ([[value valueForKey:#"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]])
{
[mutableArray addObject:[value valueForKey:#"name"]];
}
}
Edit. 1.
Try it with this plist.
Make sure you use a plain text editor to paste it into and save as a plist file
Edit.2 .
I have now updated my plist to match yours. Although the other one worked. I felt it would make more sense that we are using the same.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Whale</key>
<dict>
<key>name</key>
<string>Whale</string>
<key>isMale</key>
<true/>
<key>color</key>
<string>blue</string>
<key>maxAge</key>
<integer>8</integer>
<key>minAge</key>
<integer>3</integer>
</dict>
<key>Dolphin</key>
<dict>
<key>maxAge</key>
<integer>20</integer>
<key>name</key>
<string>Dolphin</string>
<key>isMale</key>
<false/>
<key>color</key>
<string>blue</string>
<key>minAge</key>
<integer>15</integer>
</dict>
</dict>
</plist>
Also, here is another example showing how to compare the boolean and number together
NSMutableArray *theAnimalMatched =[[NSMutableArray alloc] initWithObjects:nil];
NSDictionary *mainDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"data1" ofType:#"plist"]];
//---enumerate through the dictionary objects inside the rootDictionary
NSEnumerator *enumerator = [mainDictionary objectEnumerator];
id returnValue;
while ((returnValue = [enumerator nextObject])) {
if ( [[returnValue valueForKey:#"isMale" ] boolValue] && [[returnValue valueForKey:#"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]] && [[returnValue valueForKey:#"color"] isEqualToString:#"blue"] )
{
[theAnimalMatched addObject:[returnValue valueForKey:#"name"]];
}
}
Instead of the following line
if ([[newArray objectAtIndex:i]objectForKey:#"minAge"] == [NSNumber numberWithInt:3])
try the following
if ( [[[newArray objectAtIndex:i]objectForKey:#"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]])

transforming a plist in another nsdictionary

I'm not english, new to objective c and new to this website. But i hope you will understand my problem. I tried to use the search engine but i couldn't find a answer...
THE PROBLEM:
i have a plist file like this
<plist version="1.0">
<array>
<dict>
<key>ID</key>
<string>001</string>
<key>CAT</key>
<string>A</string>
<key>TITLE</key>
<string>AAAA01</string>
</dict>
<dict>
<key>ID</key>
<string>002</string>
<key>CAT</key>
<string>A</string>
<key>TITLE</key>
<string>AAAA02</string>
</dict>
<dict>
<key>ID</key>
<string>003</string>
<key>CAT</key>
<string>B</string>
<key>TITLE</key>
<string>BBBB01</string>
</dict>
.....
</array>
</plist>
so i have many entries like this. every entry has a category (CAT) like in my example "A" and "B".
now i need a code to transform this to the following:
NSArray
NSDictionary
CAT => "A"
VALUES => {"AAAA01","AAAA02"}
NSDictionary
CAT => "B"
VALUES => {"BBBB01", ...}
ETC.
MY SOLUTION:
i get the plist with the following code
NSString *path = [[NSBundle mainBundle] pathForResource:#"Dictonary" ofType:#"plist"];
arrayIndex = [[NSArray alloc] initWithContentsOfFile:path];
Now i have everything saved in the arrayIndex but then i dont find a way to transform the code in a new array to get my wanted result.
please can anybody help me?
THANK YOU very much!
This is straight programming.
It is more easily done in two steps saving trying to find an entry to add to.
// First create a dictionary of CAT and the values,
NSMutableDictionary *tempDict = [NSMutableDictionary dictionary];
for (NSDictionary *item in arrayIndex) {
NSString *cat = [item valueForKey:#"CAT"];
NSMutableArray *tempArray = [tempDict valueForKey:cat];
if (!tempArray) {
tempArray = [NSMutableArray array];
[tempDict setValue:tempArray forKey:cat];
}
NSString *v = [item valueForKey:#"TITLE"];
[tempArray addObject:v];
}
NSLog(#"tempDict: %#", tempDict);
// This may well be a good final result
// This step transforms the dictionary into a list of dictionaries
NSMutableArray *newList = [NSMutableArray array];
NSArray *keys = [[tempDict allKeys] sortedArrayUsingSelector:#selector(compare:)];
for (NSString *cat in keys) {
[newList addObject:[NSDictionary dictionaryWithObjectsAndKeys:
cat, #"CAT",
[tempDict valueForKey:cat], #"VALUES",
nil]];
}
NSLog(#"newList: %#", newList);