read multi-array from plist - objective-c

I can't get it work to have the 8 items from the plist below.
I have a plist "settings.plist". Now I wan't from vragen -> category (self.catagorie - 1) -> question. The 8 items. But the array keeps empty.
What am I doing wrong?
Code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"instellingen.plist"];
NSMutableDictionary *instellingen = [NSMutableDictionary dictionaryWithContentsOfFile:path];
NSArray *vragen = [instellingen objectForKey:#"vragen"];
NSArray *cata = [vragen objectAtIndex: (self.catagorie-1)];
NSArray *question = [cata objectAtIndex: 0];
NSLog(#"count: %i", [question count]);
Plist file:
<?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>vragen</key>
<array>
<array> <--catagorydata
<array> <-- questiondata
<string>vraag</string>
<string>A</string>
<string>B</string>
<string>C</string>
<string>D</string>
<string>1</string>
<string>standaard</string>
<string></string>
</array>
<array>
<string>vraag2</string>
<string>A</string>
<string>B</string>
<string>C</string>
<string>D</string>
<string>1</string>
<string>afbeelding</string>
<string>afbeelding.jpg</string>
</array>
</array>
</array>
<key>firstBoot</key>
<true/>
<key>regelAtRuntime</key>
<true/>
</dict>
</plist>

First of all this line
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"instellingen.plist"]; ?
should be
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"settings.plist"];
I also had to delete these from the dictionary:
<--catagorydata
<-- questiondata
Besides the two things above, there is nothing wrong with your code or your dictionary.
After making those changes I tested your code and the output I got was:
tester[69637:c07] size of dict 3
tester[69637:c07] count: 8
which is correct according to the .plist file
So your problem is at the first 4 lines. Make sure your file is in Documents directory (use something like the following code to see whats going wrong)
NSLog(#"Path : %#",path);
I copied the file in the project folder (because I used the simulator) and used the following code and everything worked fine
NSBundle* b=[NSBundle mainBundle];
NSURL* path1=[b URLForResource:#"settings" withExtension:#"plist"];
NSMutableDictionary *instellingen = [NSMutableDictionary dictionaryWithContentsOfURL:path1];
NSLog(#"size of dict %d",[instellingen count]);
NSArray *vragen = [instellingen objectForKey:#"vragen"];
NSArray *cata = [vragen objectAtIndex: 0];
NSArray *question = [cata objectAtIndex: 0];
NSLog(#"count: %i", [question count]);

Just a quick read, but looks like you have an array of "categoryData" items, that contains an array of questionData items; questionData items are strings.
NSArray *vragen = [instellingen objectForKey:#"vragen"]; // count = 1
NSArray *cata = [vragen objectAtIndex: (self.catagorie-1)]; // count = 2
NSString *question = [cata objectAtIndex: 0];
Recommend you add some breakpoints and look at your data. OR, NSLog(#"data = %#", cata); etc.

Related

How to Load Plist to UITableView Objective-C

I have this plist setup:
<?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>area</key>
<string>area1</string>
<key>shop</key>
<string>shop1</string>
<key>location</key>
<string>2nd Floor</string>
<key>coordinates</key>
<string>14.733836,121.058221</string>
</dict>
<dict>
<key>area</key>
<string>area1</string>
<key>shop</key>
<string>shop2</string>
<key>location</key>
<string>Ground Floor</string>
<key>coordinates</key>
<string>14.733836,121.058221</string>
</dict>
<dict>
<key>area</key>
<string>area2</string>
<key>shop</key>
<string>shop1</string>
<key>location</key>
<string>2nd Floor</string>
<key>coordinates</key>
<string>14.656918,121.029795</string>
</dict>
<dict>
<key>area</key>
<string>area2</string>
<key>shop</key>
<string>shop2</string>
<key>location</key>
<string>Ground Floor</string>
<key>coordinates</key>
<string>14.656918,121.029795</string>
</dict>
</array>
</plist>
How can I plot this inside my UITableView? My header titles will be the key "area" while the table cell labels the key "shop" and the subtitle labels the key "location". The coordinates key will be used to plot it on the mapview that loads when the user taps the table cell.
Thanks in advance!
- (UITableViewCell *)tableView:cellForRowAtIndexPath:
NSDictionary *dict = [array objectAtIndex: indexPath.section];
cell.textLabel.text = [dict objectForKey: #"shop"];
cell.detailTextLabel.text = [dict objectForKey: #"location"];
- (NSString *)tableView:titleForHeaderInSection:
NSDictionary *dict = [array objectAtIndex: indexPath.section];
NSString *area = [dict objectForKey: #"area"];
return area;
- (void)tableView:didSelectRowAtIndexPath:
NSDictionary *dict = [array objectAtIndex: indexPath.section];
NSString *coordinates = [dict objectForKey: #"coordinates"];
newViewController.coordinates = coordinates
You have to create 3 NSDictionary.
Dict 1: titles
Dict 2: celltexts
Dict 3: subtitles
NSDictionary *dictTitles = [[NSDictionary dictionaryWithContentsOfFile:#"filepathtoyourplist"] valueForKey:#"Titles"];
Then put it into an array
NSArray *titleArray = [[NSArray alloc] initWithDictionary:dictTitles];
in your titlesForHeaderInSection
headertitle = [titlearray objectAtIndex:indexPath.row];
Do the steps for cell text and subtitle again.
you can try this :
//In your .h file
NSArray *array;
//In your .m file
- (void)viewDidLoad {
// Some code...
NSString *path = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"plist"];
array = [NSArray arrayWithContentsOfFile:path];
// Some code...
}
Then you create a new NSObject class and for each cell you init your object, for example :
MyClass *newInstance = [[MyClass alloc] init];
newInstance.area = [array objectForKey:#"area"];
newInstance.shop = [array objectForKey:#"shop"];
newInstance.location = [array objectForKey:#"location"];
newInstance.coordinates = [array objectForKey:#"coordinates"];
Hope it helps :)

Problems extracting values from NSMutableArray

I'm trying to parse data from a plist file into a NSMutableArray.
In my plist
Root is a Dictionary containing an Array of 6 Numbers
I've created a label hooked with the IBOutlet UILabel *lbl4 object and I want this label to show the first element of the array made reading the plist. The problem is that the program crashes at the assigning instruction (the last one).
My code is this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths objectAtIndex:0];
NSString *plistPath = [docPath stringByAppendingPathComponent:#"settings.plist"];
if(![[NSFileManager defaultManager] fileExistsAtPath:plistPath]);
{
plistPath = [[NSBundle mainBundle] pathForResource:#"settings" ofType:#"plist"];
}
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *err = nil;
NSPropertyListFormat format;
NSDictionary *temp = (NSDictionary *) [NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&err];
if(!temp)
{
NSLog(#"Error reading plist: %#, format: %d", err, format);
}
self.dataSet = [NSMutableArray arrayWithArray:[temp objectForKey:#"Dadi"]];
[lbl4 setText:[NSString stringWithFormat:#"%#", [dataSet objectAtIndex:0]]];
The plist source code is the following:
<?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>Dadi</key>
<array/>
<key>D4</key>
<integer>0</integer>
<key>D6</key>
<integer>0</integer>
<key>D8</key>
<integer>0</integer>
<key>D10</key>
<integer>0</integer>
<key>D12</key>
<integer>0</integer>
<key>D20</key>
<integer>0</integer>
</dict>
</plist>
The Debug output says "2012-09-02 18:29:55.483 Faith[6014:707] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'"
In your plist, the array stored at the dictionary's Dadi key is empty!
<key>Dadi</key>
<array/>
So
self.dataSet = [NSMutableArray arrayWithArray:[temp objectForKey:#"Dadi"]];
Sets self.dataSet to an empty array (i.e. even index:0 is beyond the bounds).
I would check for se.f.dataSet.count == 0 and provide a default in this case.
#warrenm mentioned in the comments that the structure of your plist is not what you might have expected. These are XML files, so any tag which ends with /> is "self-closing", and therefore always empty. To contain those numbers, you need to add an ending tag and place them inside:
<array>
<integer>7</integer>
</array>
Of course, on further evaluation, your existing plist has keys associated with those, so this is possibly also not the right solution. You'll need to evaluate what your needs are for that plist.

NSArray initWithContentsOfFile returns nil

I'm trying to read a plist file into NSArray using initWithContentsOfFile as described here
My code looks like this
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:
#"routes" ofType:#"plist" ];
routes = [[NSArray alloc] initWithContentsOfFile:plistPath ];
NSLog:(#"contents of myArray %#", routes);
routes.plist has a perfectly simple structure of array and 2 string values inside
<?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>Root</key>
<array>
<string>1</string>
<string>2</string>
</array>
</dict>
</plist>
Everything seems to be fine. plistPath initializes with correct value, which means file is copied to the bundle and can be readed. But routes = [[NSArray alloc] initWithContentsOfFile:plistPath ]; returns 0x0 value. I think this is equal to nil
What is wrong with my code?
Actually your plist is a dictionary.
Change this:
<dict>
<key>Root</key>
<array>
<string>1</string>
<string>2</string>
</array>
</dict>
to this:
<array>
<string>1</string>
<string>2</string>
</array>
I think you want to do something like this:
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:
#"routes" ofType:#"plist"];
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSArray *routes = [dictionary objectForKey:#"Root"];

How to use arrayWithContentsOfFile to load file successfully written with writeToFile in ObjectiveC/XCode

I am saving an array of custom objects to a plist list file like so:
+(void) arrayToPlist: (NSArray*) plant_types{
NSMutableArray* dictionary_array = [NSMutableArray arrayWithCapacity: plant_types.count];
for(int i = 0; i<plant_types.count; i++){
PlantType* pt = [plant_types objectAtIndex: i];
[dictionary_array addObject: [pt toDict]];
}
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* filePath = [rootPath stringByAppendingPathComponent:#"PlantTypes.plist"];
NSLog(#"Writing plist to: %#", filePath);
[dictionary_array writeToFile: filePath atomically: YES];
}
Which creates a file that looks like:
<?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>Autumn Olive</string>
<key>radius</key>
<real>10</real>
</dict>
<dict>
<key>name</key>
<string>Dwarf Cherry</string>
<key>radius</key>
<real>5</real>
</dict>
<dict>
<key>name</key>
<string>Bamboo</string>
<key>radius</key>
<real>2</real>
</dict>
<dict>
<key>name</key>
<string>Pomegranate</string>
<key>radius</key>
<real>6</real>
</dict>
<dict>
<key>name</key>
<string>Lupin</string>
<key>radius</key>
<real>0.60000002384185791</real>
</dict>
</array>
</plist>
And loading them this way:
+(NSMutableArray*) arrayFromPlist{
NSLog(#"Loading array of plant types from plist.");
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* filePath = [rootPath stringByAppendingPathComponent:#"PlantTypes.plist"];
NSFileManager* fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:filePath]){
NSLog(#"Plist file exists at expected location.");
NSMutableArray* plant_dicts = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"Loaded array with contents of file, got %d plant types.", plant_dicts.count);
NSMutableArray* plant_types = [NSMutableArray arrayWithCapacity: plant_dicts.count];
for(int i = 0; i< plant_dicts.count; i++){
NSMutableDictionary* dict = [plant_dicts objectAtIndex: i];
[plant_types addObject: [PlantType fromDict: dict]];
}
return plant_types;
}
NSLog(#"Plant Type plist file not found.");
return NULL;
}
Nothings crashing, but every time I return a NSMutableArray of size zero (and that logging statement confirms that plant_dicts is of size zero).
What am I doing wrong? All the similar problems I'm seeing with arrayWithContentsOfFile: is people creating the plist by hand or with an editor...I'd think making it from the code itself wouldn't have these problems...
Edit: I have confirmed that I'm no longer getting a size zero result (which is weird, there have been no code changes in that section since the original post). However, I'm still not loading things correctly. Here is my fromDict and toDict Methods.
The problem is that the string "shape" doesn't seem to be loading right. At least, when I ask if shape == #"Circle" I get that it doesn't, even if it clearly does in the NSLog statement. I am making an identical comparison elsewhere in the code (when checking how to render the object) and it works fine there (so I assume there isn't some weird == vs .equals like there is in Java).
Double Edit: Wait, no there is [shape isEqualToString: #"Circle"]....why I didn't need to use it before confuses me, but adding it here helps.
With your plist, this code return a correct result
+(NSMutableArray*) arrayFromPlist{
NSLog(#"Loading array of plant types from plist.");
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* filePath = [rootPath stringByAppendingPathComponent:#"PlantTypes.plist"];
NSFileManager* fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:filePath]){
NSLog(#"Plist file exists at expected location.");
NSMutableArray* plant_dicts = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"Loaded array with contents of file, got %d plant types.", plant_dicts.count);
NSMutableArray* plant_types = [NSMutableArray arrayWithCapacity: plant_dicts.count];
for(int i = 0; i< plant_dicts.count; i++){
NSMutableDictionary* dict = [plant_dicts objectAtIndex: i];
[plant_types addObject: dict];
}
return plant_types;
}
NSLog(#"Plant Type plist file not found.");
return NULL;
}
result
2012-02-22 16:24:43.697 Test[5574:10103] Loading array of plant types from plist.
2012-02-22 16:24:43.698 Test[5574:10103] Plist file exists at expected location.
2012-02-22 16:24:43.699 Test[5574:10103] Loaded array with contents of file, got 5 plant types.
2012-02-22 16:24:43.700 Test[5574:10103](
{
name = "Autumn Olive";
radius = 10;
},
{
name = "Dwarf Cherry";
radius = 5;
},
{
name = Bamboo;
radius = 2;
},
{
name = Pomegranate;
radius = 6;
},
{
name = Lupin;
radius = "0.6000000238418579";
}
)
I think problem come from your PlantType implementation. Can you post your code (toDict and fromDict methods)
This line:
NSMutableDictionary* dict = [plant_dicts objectAtIndex: i];
does not return a mutable dictionary, but an immutable one.
If you want it to be mutable, you should do something along these lines:
MutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary: [plant_dicts objectAtIndex: i]];

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);