Search code examples
objective-cplist

Save data to plist in xcode


I understand that you have to retrieve data from plist first, add data, and rewrite the entire contents to the plist file.

But my code here is NOT appending, but refreshing every time I call this method.

- (void) saveDataToPlist {
    // Retrieve path and filename of the plist file
    NSString *myColorsListFile = [self dataFilePath];

    NSMutableArray  *innerArray1;
    NSString *error;

    UserGivenColorHexString = HexTextField.text;
    NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:100];

    if ([[NSFileManager defaultManager] fileExistsAtPath:myColorsListFile]) {
        // File exists
        rootObj = [[NSMutableDictionary alloc] initWithContentsOfFile:myColorsListFile];


        [innerArray1 addObjectsFromArray:[NSMutableArray arrayWithContentsOfFile:myColorsListFile]];
        [innerArray1 addObject:UserGivenColorName];

    } else {
        // Create file
        rootObj = [[NSMutableDictionary alloc] init];

        innerArray1 = [NSMutableArray arrayWithObjects: UserGivenColorName, nil];
        [rootObj setObject:innerArray1 forKey:@"ColorName"];
    }

    id plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];

    [plist writeToFile:myColorsListFile atomically:YES];
}

Solution

  • There seem to be a bunch of issues: The key problem is that you are not setting the innerArray1 variable if the plist was found, so your attempts to add to it will be for naught. After loading rootObj with the contents of the plist, you have to obtain a reference to the array located at the key ColorName:

    innerArray1 = [rootObj objectForKey:@"ColorName"];
    

    Then the code will work.

    Unrelated to this immediate isse, there are a few other minor issues:

    • You are reading the dictionary with the myColorsListFile plist, but you also try to add the contents of this as an array to innerArray1. That latter use of myColorsListFile strikes me as an invalid use of this plist. I'd remove that line.

    • It appears that you set UserGivenColorHexString, but then save UserGivenColorName (I might also change this to a local variable to avoid unintended consequences elsewhere). I assume you meant to use the same variable for both of these.

    • You're also instantiating mutable dictionary that you're subsequently discarding.

    • I might suggest conforming to Cocoa Naming Conventions (start variables with lowercase letters). I also presumed that hexTextField was really a property.

    • It might be a little more robust to separate "does the file exist" logic from the "did I find ColorName array" logic.

    • Since you're capturing the plist creation failure error, you might as well log it if you encounter it.

    • The documentation tells us that dataFromPropertyList is now obsolete:

      Special Considerations

      This method is obsolete and will be deprecated soon. Use dataWithPropertyList:format:options:error: instead.

    So, you might end up with something like:

    - (void) saveDataToPlist {
        // Retrieve path and filename of the plist file
        NSString *myColorsListFile = [self dataFilePath];
    
        NSMutableArray  *innerArray1;
        NSError *error;
    
        NSString *userGivenColorHexString = HexTextField.text;
        NSMutableDictionary *rootObj;
    
        if ([[NSFileManager defaultManager] fileExistsAtPath:myColorsListFile]) {
            rootObj = [[NSMutableDictionary alloc] initWithContentsOfFile:myColorsListFile];
        } else {
            rootObj = [[NSMutableDictionary alloc] init];
        }
    
        innerArray1 = [rootObj objectForKey:@"ColorName"];
    
        if (innerArray1) {
            [innerArray1 addObject:userGivenColorHexString];
        } else {
            innerArray1 = [NSMutableArray arrayWithObjects: userGivenColorHexString, nil];
            [rootObj setObject:innerArray1 forKey:@"ColorName"];
        }
    
        id plist = [NSPropertyListSerialization dataWithPropertyList:(id)rootObj format:NSPropertyListXMLFormat_v1_0 options:0 error:&error];
        if (!plist) {
            NSLog(@"dataFromPropertyList error: %@", error);
        }
    
        [plist writeToFile:myColorsListFile atomically:YES];
    }