0

I want to be able to take an object and write out all its properties to a PLIST. I got so far with this:

// Get the properties of the parent class
NSMutableArray *contentViewPropertyNames = [self propertyNamesOfObject:[contentView superclass]];

// Add the properties of the content view class
[contentViewPropertyNames addObjectsFromArray:[self propertyNamesOfObject:contentView]];

// Get the values of the keys for both the parent class and the class itself
NSDictionary *keyValuesOfProperties = [contentView dictionaryWithValuesForKeys:contentViewPropertyNames];

// Write the dictionary to a PLIST
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:[dataFileName stringByAppendingString:@".plist"]];

[keyValuesOfProperties writeToFile:pathAndFileName atomically:YES];

All good, except I can't write this to a PLIST because it contains some properties that are not compliant with PLISTs, so writeToFile:atomically: fails and returns NO.

Is there a good way to serialize only those properties that are serailizable into a PLIST or modify the base class of my objects to make this work?

I realise I could archive to a binary file no problem with NSCoding however I need to be able to transfer the output between a MacOS application and an iOS app, so need to go via an intermediate, platform independent format.

Of course I could be missing the point entirely, if I have please do tell, and as always, any help is useful.

Best regards

Dave

P.S.

Here is my method to get the property names of an object:

- (NSMutableArray *)propertyNamesOfObject:(id)object {
    NSMutableArray *propertyNames = nil;
    unsigned int count, i;
    objc_property_t *properties = class_copyPropertyList([object class], &count);

    if (count > 0) {
        propertyNames = [[[NSMutableArray alloc] init] autorelease];

        for(i = 0; i < count; i++) {
            objc_property_t property = properties[i];
            const char *propName = property_getName(property);
            if(propName) {
                NSString *propertyName = [NSString stringWithCString:propName encoding:NSUTF8StringEncoding];
                [propertyNames addObject:propertyName];
            }
        }
    }
    free(properties);

    return propertyNames;
}
Magic Bullet Dave
  • 9,006
  • 10
  • 51
  • 81

1 Answers1

0

See if you can apply this function I recently wrote in a similar situation:

// Property list compatible types: NSString, NSData, NSArray, or NSDictionary */
- (BOOL)isPlistCompatibleDictionary:(NSDictionary *)dict {
    NSSet *plistClasses = [NSSet setWithObjects:[NSString class], [NSData class],
        [NSArray class], [NSDictionary class], [NSDate class], 
        [NSNumber class], nil];

    BOOL compatible = YES;
    NSArray *keys = [dict allKeys];
    for (id key in keys) {
        id obj = [dict objectForKey:key];
        if (![plistClasses containsObject:[obj class]]) {
            NSLog(@"not plist compatible: %@", [obj class]);
            compatible = NO;
            break;
        }
    }

    return compatible;
}
Jere Käpyaho
  • 1,305
  • 1
  • 10
  • 29
  • This looks great Jere. I'll give it a go and let you know how I get on. Dave. – Magic Bullet Dave Oct 05 '12 at 06:44
  • The approach looks good, however for some reason all my obj classes are being reported as __NSCFString rather than their proper types and so the compatibility check returns NO for every key. Any ideas? – Magic Bullet Dave Oct 05 '12 at 07:33
  • Hmm, any help in this? http://stackoverflow.com/questions/393873/nsstring-instance-reports-its-class-as-nscfstring – Jere Käpyaho Oct 05 '12 at 10:34