File Tree Structure into NSDictionary - objective-c

I'm trying to read a full File/Folder Structure (starting from a given Folder) into an NSDictionary (with a NSArrays,etc), like this :
Let's say starting folder is : /Users/some-user/some-path
We go in there and list all folders/subfolders/files
A/
file_a.txt
file_b.txt
subfolder/
file_c.txt
B/
etc...
What I want is to convert this file structure (probably using enumerators and NSFileManager) into an NSDictionary like :
<key>folder</key>
<string>A</string>
<key>values</key>
<array>
<dict>
<key>file</key>
<string>file_a.txt</string>
<key>url</key>
<string>/Users/some-user/some-path/A/file_a.txt</string>
</dict>
<dict>
<key>file</key>
<string>file_b.txt</string>
<key>url</key>
<string>/Users/some-user/some-path/A/file_b.txt</string>
</dict>
<dict>
<key>folder</key>
<string>subfolder</string>
<key>values</key>
<array>
...
</array>
</dict>
</array>
Any ideas?

Well this is the working result :
To check if a path is a Directory/Package/Bundle, etc :
- (BOOL)isDir:(NSString*)path
{
BOOL isDir;
if (([[NSFileManager defaultManager]
fileExistsAtPath:path isDirectory:&isDir] && isDir) ||
([[NSWorkspace sharedWorkspace] isFilePackageAtPath:path]))
return YES;
else
return NO;
}
The actual function (using recursion) :
- (NSArray*)getContents:(NSString*)path {
NSError* err = nil;
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&err];
NSMutableArray* conts = [[NSMutableArray alloc] initWithObjects: nil];
for (NSString* c in files)
{
NSDictionary* d;
NSString* p = [d stringByAppendingPathComponent:d];
if (![self isDir:p])
{
d = [NSDictionary dictionaryWithObjectsAndKeys:
c,#"name",
p,#"url", nil];
}
else
{
d = [NSDictionary dictionaryWithObjectsAndKeys:
c,#"group",
p,#"entries", nil];
}
[conts addObject:d];
}
return conts;
}

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;
}
}];

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

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

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