Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 841
J.R. Avatar asked Feb 18 '12 16:02

J.R.


1 Answers

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)

like image 128
Mathieu Hausherr Avatar answered Oct 05 '22 17:10

Mathieu Hausherr