20

If I have an NSManagedObject I've fetched from a context, how can I create an NSDictionary out of its dynamic properties without just copying each field into the dictionary explicitly?

If my managed object looks like this, for example:

@implementation Track

@dynamic artist;
@dynamic group;
@dynamic purchase_url;
@dynamic title;
@dynamic file_name;
@dynamic year;

@end

After fetching from the database, in this case, I need an NSDictionary with the same properties set to each of those @dynamic properties.

typeoneerror
  • 55,990
  • 32
  • 132
  • 223
  • 1
    Could you give more detail about why you want to do this, there may be a better way to achieve what you want. In the meantime, look at NSEntityDescription and attributesByName. – jrturton Apr 26 '12 at 21:23
  • 1
    Have a look at [this article](http://vladimir.zardina.org/2010/03/serializing-archivingunarchiving-an-nsmanagedobject-graph/). It also covers you for any relations as well. – Alladinian Apr 26 '12 at 21:23

4 Answers4

57

There is a faster way to convert an NSManagedObject to an NSDictionary (from Matthias Bauch response at https://stackoverflow.com/a/5664745/2294824) :

NSArray *keys = [[[myObject entity] attributesByName] allKeys];
NSDictionary *dict = [myObject dictionaryWithValuesForKeys:keys];
Community
  • 1
  • 1
Frédéric
  • 726
  • 8
  • 8
12

You can achieve your approach by following method:

unsigned int count;
objc_property_t *properties = class_copyPropertyList([CoreDataObject class], &count);
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:16];

for(int i = 0; i < count; i++) {
    objc_property_t property = properties[i];
    NSString *name = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
    id obj = [coreDataObjectInstance valueForKey:name];
    if (obj) {
        // Skip properties with nil values (optionally you can use: [dictionary setObject:((obj == nil) ? [NSNull null] : obj) forKey:name]; without any if-statement) 
        [dictionary setObject:obj forKey:name];
    }
}

free(properties);

"CoreDataObject" is the core data object you would like to convert into a NSDictionary while "coreDataObjectInstance" is an instance of this core data object. Keep in mind you have to:

#include <objc/runtime.h>

Furthermore, it would be great if you can give us some more insights what you would like to achieve with this idea, maybe there is a different/better solution.

Hope this helps!

Markus
  • 585
  • 7
  • 18
  • I would like to share with you details about what I may use this in, I want to make an inspector window, so if you selected a row in a table populated with nsmanagedobject subclass, the inspector window will show the properties of this managedObject in three columns tale: property name, property type "string, int..." and prop value what do you think the best way to achieve this scenario?? – AMTourky Dec 04 '13 at 12:49
7

I think this is what you're actually looking for:

NSEntityDescription *trackEntity = [NSEntityDescription entityForName:[Track entityName] inManagedObjectContext:yourMOC];

then you have access to these dictionaries:

[trackEntity propertiesByName];
[trackEntity relationshipsByName];
[trackEntity attributesByName];

each of these dictionaries will have keys corresponding to the property, and the value will be an NSPropertyDescription.

bpercevic
  • 450
  • 6
  • 14
3

Note: Swift 4.2 update

let keys = Array(YOUR_MANAGED_OBJECT.entity.attributesByName.keys)
let data:[String: Any] = YOUR_MANAGED_OBJECT.dictionaryWithValues(forKeys: keys)
ceekay
  • 1,136
  • 13
  • 11
  • 2
    **Swift 5:** `let data = YOUR_MANAGED_OBJECT.dictionaryWithValues(forKeys: YOUR_MANAGED_OBJECT.attributeKeys)` – Daniel Jan 12 '20 at 20:15