-
-
Save tapi/2489095 to your computer and use it in GitHub Desktop.
// | |
// NSObject+SMDictionaryMapping.h | |
// SoundTrack | |
// | |
// Created by Paddy O'Brien on 12-04-24. | |
// Copyright (c) 2012 Paddy O'Brien. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol SMMappedObject <NSObject> | |
+ (NSDictionary *)mappedKeys; | |
@end | |
@interface NSObject (SMDictionaryMapping) | |
- (id)initWithDictionary:(NSDictionary *)dictionary; | |
- (void)updateWithDictionary:(NSDictionary *)dictionary; | |
@end |
// | |
// NSObject+DictionaryMapping.m | |
// SoundTrack | |
// | |
// Created by Paddy O'Brien on 12-04-24. | |
// Copyright (c) 2012 Paddy O'Brien. All rights reserved. | |
// | |
#import "NSObject+DictionaryMapping.h" | |
@interface NSObject () | |
- (void)mapDictionaryToProperties:(NSDictionary *)dictionary; | |
@end | |
@implementation NSObject (DictionaryMapping) | |
- (id)initWithDictionary:(NSDictionary *)dictionary | |
{ | |
if (self) { | |
[self mapDictionaryToProperties:dictionary]; | |
} | |
return self; | |
} | |
- (void)updatePropertiesWithDictionary:(NSDictionary *)dictionary | |
{ | |
[self mapDictionaryToProperties:dictionary]; | |
} | |
- (void)mapDictionaryToProperties:(NSDictionary *)dictionary | |
{ | |
NSArray* keys = [dictionary allKeys]; | |
for (NSString *key in keys) { | |
NSString *mappedKey = key; | |
if ([self conformsToProtocol:@protocol(SMMappedObject)] && [self respondsToSelector:@selector(mappedKeys)]) { | |
NSDictionary *mappedKeys = [self performSelector:@selector(mappedKeys)]; | |
if ([mappedKeys valueForKey:key]) { | |
mappedKey = [mappedKeys valueForKey:key]; | |
} | |
} | |
[self setValue:[dictionary valueForKey:key] forKey:mappedKey]; | |
} | |
} | |
@end |
// | |
// NSObject+SMDictionaryMapping.h | |
// | |
// Created by Paddy O'Brien on 12-04-24. | |
// Copyright (c) 2012 Paddy O'Brien. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol SMMappedObject <NSObject> | |
+ (NSDictionary *)mappedKeys; | |
@end | |
@interface NSObject (SMDictionaryMapping) | |
- (id)initWithDictionary:(NSDictionary *)dictionary; | |
- (void)updateWithDictionary:(NSDictionary *)dictionary; | |
@end |
// | |
// NSObject+DictionaryMapping.m | |
// | |
// Created by Paddy O'Brien on 12-04-24. | |
// Copyright (c) 2012 Paddy O'Brien. All rights reserved. | |
// | |
#import "NSObject+DictionaryMapping.h" | |
@interface NSObject () | |
- (void)mapDictionaryToProperties:(NSDictionary *)dictionary; | |
@end | |
@implementation NSObject (DictionaryMapping) | |
- (id)initWithDictionary:(NSDictionary *)dictionary | |
{ | |
if (self) { | |
[self mapDictionaryToProperties:dictionary]; | |
} | |
return self; | |
} | |
- (void)updatePropertiesWithDictionary:(NSDictionary *)dictionary | |
{ | |
[self mapDictionaryToProperties:dictionary]; | |
} | |
- (void)mapDictionaryToProperties:(NSDictionary *)dictionary | |
{ | |
NSArray* keys = [dictionary allKeys]; | |
for (NSString *key in keys) { | |
NSString *mappedKey = key; | |
if ([self conformsToProtocol:@protocol(SMMappedObject)] && [self respondsToSelector:@selector(mappedKeys)]) { | |
NSDictionary *mappedKeys = [self performSelector:@selector(mappedKeys)]; | |
if ([mappedKeys valueForKey:key]) { | |
mappedKey = [mappedKeys valueForKey:key]; | |
} | |
} | |
id value = ([[dictionary valueForKey:key] isKindOfClass:[NSNull class]]) ? nil : [dictionary valueForKey:key]; | |
[self setValue:value forKey:mappedKey]; | |
} | |
} | |
@end |
Yes but what if you actually want a dictionary as a property on an object? Interogate the class of the property to see if it conforms to the protocol perhaps?
@warwick an example might look like this
@interface Contact : NSObject <SMMappedObject>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) Email *email;
@end
Later we want to get a bunch of contacts from some webservice that spits back JSON
- (NSArray *)getMyContacts
{
NSData *JSONData = [MagicWebRequestThatRequiresNoSetup GetURL:@"www.myaddressbook.com/contacts"];
NSArray *contacts = [JSONData parseObjectFromJSON];
NSMutableArray* retval = [NSMutableArray array];
for (NSDictionary *contactData in contact) {
Contact *newContact = [[Contact alloc] initWithDictionary:contactData];
[retval addObject:newContact];
}
return retval;
}
The idea is to have you local domain object populated without having to slog through writing your own mappings.
I'm curious about sub-entities and arrays of sub-entities, too. Would it be best to define those in the model class as an array of strings (JSON key names) you want explicitly mapped to sub-entities? One thing all of my JSON keys have in common is that the sub-entity keys are all upper-case first character. This could be the "auto" mode; if a mapped key is upper-case first character it looks for a model class of same name and maps accordingly. I haven't looked to see what something like RestKit does. Just seems like something that could be a single NSObject category rather than a giant library.
Well, your current approach would work except if you're being passed in a sub-entity (like the user model of a photo model). So you could do something like this:
Thoughts?