wenlong1423
9/3/2015 - 4:30 PM

Playing with NSPropertyListSerialization

Playing with NSPropertyListSerialization

#import <Foundation/Foundation.h>

// clang -g -Wall -fobjc-arc -framework Foundation -o serial serial.m


static id makePlistObjects (void) {
    NSMutableDictionary *top = [NSMutableDictionary dictionary];

    [top setObject: @"Hi I'm a string"  forKey: @"string"];
    [top setObject: [NSNumber numberWithInt: 23]  forKey: @"number"];
    [top setObject: [NSNumber numberWithBool: YES]  forKey: @"boolean"];
    [top setObject: [NSDate date]  forKey: @"date"];
    [top setObject: [NSData dataWithBytes: "badger"  length: 7] forKey: @"data"];

    NSArray *array =
        [NSArray arrayWithObjects: @"I", @"seem", @"to", @"be", @"a", @"verb", nil];
    [top setObject: array  forKey: @"array"];

    NSDictionary *dict =
        [NSDictionary dictionaryWithObjectsAndKeys:
                      @"Ack", @"Oop",
                      @"Bill the Cat", @"It's", nil];
    [top setObject: dict  forKey: @"dictionary"];

    return top;

} // makePlistObjects


// --------------------------------------------------
// Writing and reading property list objects

static void saveAsOpenStep (id plist) {
    if (![NSPropertyListSerialization
             propertyList: plist
             isValidForFormat: kCFPropertyListOpenStepFormat]) {
        NSLog (@"can't save as open step");
        return;
    }

    // Turns out you can't save as open step any more - just read them.  Bummer.
    
} // saveAsOpenStep


static void saveAsXML (id plist) {
    if (![NSPropertyListSerialization 
             propertyList: plist
             isValidForFormat: kCFPropertyListXMLFormat_v1_0]) {
        NSLog (@"can't save as XML");
        return;
    }

    NSError *error;
    NSData *data = 
        [NSPropertyListSerialization dataWithPropertyList: plist
                                     format: kCFPropertyListXMLFormat_v1_0
                                     options: 0
                                     error: &error];
    if (data == nil) {
        NSLog (@"error serializing to xml: %@", error);
        return;
    }

    BOOL writeStatus = [data writeToFile: @"plist.xml"
                             options: NSDataWritingAtomic
                             error: &error];
    if (!writeStatus) {
        NSLog (@"error writing to file: %@", error);
        return;
    }

} // saveAsXML


static void saveAsBinary (id plist) {
    if (![NSPropertyListSerialization 
             propertyList: plist
             isValidForFormat: kCFPropertyListBinaryFormat_v1_0]) {
        NSLog (@"can't save as binary");
        return;
    }

    NSError *error;
    NSData *data = 
        [NSPropertyListSerialization dataWithPropertyList: plist
                                     format: kCFPropertyListBinaryFormat_v1_0
                                     options: 0
                                     error: &error];
    if (data == nil) {
        NSLog (@"error serializing to xml: %@", error);
        return;
    }

    BOOL writeStatus = [data writeToFile: @"plist.bin"
                             options: NSDataWritingAtomic
                             error: &error];
    if (!writeStatus) {
        NSLog (@"error writing to file: %@", error);
        return;
    }

} // saveAsBinary


static id readFromFile (NSString *path) {
    NSError *error;
    NSData *data = [NSData dataWithContentsOfFile: path
                           options: 0
                           error: &error];
    if (data == nil) {
        NSLog (@"error reading %@: %@", path, error);
        return nil;
    }

    NSPropertyListFormat format;
    id plist = [NSPropertyListSerialization propertyListWithData: data
                                            options: NSPropertyListImmutable
                                            format: &format
                                            error: &error];

    if (plist == nil) {
        NSLog (@"could not deserialize %@: %@", path, error);
    } else {
        NSString *formatDescription;
        switch (format) {
        case NSPropertyListOpenStepFormat:
            formatDescription = @"openstep";
            break;
        case NSPropertyListXMLFormat_v1_0:
            formatDescription = @"xml";
            break;
        case NSPropertyListBinaryFormat_v1_0:
            formatDescription = @"binary";
            break;
        default:
            formatDescription = @"unknown";
            break;
        }
        NSLog (@"%@ was in %@ format", path, formatDescription);
    }
    
    return plist;

} // readFromFile


// --------------------------------------------------
// Writing and reading JSON

static void saveAsJSON (id plist) {
    if (![NSJSONSerialization isValidJSONObject: plist]) {
        NSLog (@"can't save as JSON");
        return;
    }

    NSError *error;
    NSData *data = 
        [NSJSONSerialization dataWithJSONObject: plist
                             options: 0 // NSJSONWritingPrettyPrinted
                             error: &error];
    if (data == nil) {
        NSLog (@"error serializing to json: %@", error);
        return;
    }

    BOOL writeStatus = [data writeToFile: @"plist.json"
                             options: NSDataWritingAtomic
                             error: &error];
    if (!writeStatus) {
        NSLog (@"error writing to file: %@", error);
        return;
    }

} // saveAsJSON



static id readFromJSONFile (NSString *path) {
    NSError *error;
    NSData *data = [NSData dataWithContentsOfFile: path
                           options: 0
                           error: &error];
    if (data == nil) {
        NSLog (@"error reading %@: %@", path, error);
        return nil;
    }

    id plist = [NSJSONSerialization JSONObjectWithData: data
                                    options: 0
                                    error: &error];
    if (plist == nil) {
        NSLog (@"could not deserialize %@: %@", path, error);
    }
    
    return plist;

} // readFromJSONFile


int main (void) {
    @autoreleasepool {
        id plist = makePlistObjects ();
        NSLog (@"original plist %@", plist);

        saveAsOpenStep (plist);
        saveAsXML (plist);
        saveAsBinary (plist);

        id plist2 = readFromFile (@"plist.bin");
        NSLog (@"read plist: %@", plist2);


        // Make JSON-happy.  Can't store dates, but we can store NULLs.
        [plist removeObjectForKey: @"date"];
        [plist setObject: [NSNull null]  forKey: @"null"];

        saveAsJSON (plist);
        id plist3 = readFromJSONFile (@"plist.json");
        NSLog (@"read JSON: %@", plist3);
    }

    return 0;

} // main