Reputation: 2141
I need to set a bunch of object attributes according to an NSDictionary
supplied via JSON from a remote server. I don't want to overwrite attributes that are not in the dictionary.
Since there lot of attributes, I have long series of statements that look like this:
if (dictionary[@"address_1"] != [NSNull null])
self.configuration.userAddress1 = dictionary[@"address_1"];
The keys in the dictionary are not identical to the names of the properties; there are two different systems that grew up separately that I'm trying to make work together.
Maybe I've been doing too much Ruby coding, but it seems like there should be a better idiom in Objective-C for doing this. Any ideas?
Upvotes: 1
Views: 1731
Reputation: 90641
Another approach would be to override -setValue:forUndefinedKey:
in your class and map the keys there.
- (void) setValue:(id)value forUndefinedKey:(NSString*)key
{
static dispatch_once_t once;
static NSDictionary* map;
dispatch_once(&once, ^{
map = @{
@"address_1" : @"address1",
@"address_2" : @"address2",
// ...
};
});
NSString* newKey = map[key];
if (newKey)
[self setValue:value forKey:newKey];
else
[super setValue:value forUndefinedKey:key];
}
Now you can use -setValuesForKeysWithDictionary:
with the original dictionary. That method will do the substitution of nil
for NSNull
objects, so you have to decide if that's what you want.
You can go the other direction, too, if desired, by overriding -valueForUndefinedKey:
.
Upvotes: 0
Reputation: 38728
Sounds like you want a simple mapping solution - you can hand roll one like this
[@{
@"address_1" : @"address1",
@"address_2" : @"address2",
...
} enumerateKeysAndObjectsUsingBlock:^(NSString *remoteKey, NSString *localKey, BOOL *stop) {
id remoteValue = dictionary[remoteKey];
if (![remoteValue isEqual:NSNull.null]) {
[self.configuration setValue:remoteValue forKey:localKey];
}
}];
This applies some basic Null
checking logic and allows the remote/local objects to have different property names
Upvotes: 3
Reputation: 16660
No, it is not to rubyish, because Objective-C is dynamically typed. You can do this with key value coding:
for (NSString *key in dictionary)
{
id value = dictionary[key];
[self.configuration setValue:value forKey:key];
}
But see my comments here.
BTW: If a key does not exist in a dictionary, the result is nil
not [NSNull null]
.
So, if you do not want to set properties that are not in the dictionary, you have to do nothing additional. If you do not want to set properties that are in the dictionary with the value [NSNull null]
, you still can add the check.
If you do not want to set null's:
for (NSString *key in dictionary)
{
id value = dictionary[key];
if (value != [NSNull null] )
{
[self.configuration setValue:value forKey:key];
}
}
If you do want to set null's with nil:
for (NSString *key in dictionary)
{
id value = dictionary[key];
if (value == [NSNull null] )
{
value = nil;
}
[self.configuration setValue:value forKey:key];
}
Upvotes: 1
Reputation: 535801
One possible idiom in Objective-C would be: don't have a lot of object attributes. Have one attribute, a dictionary! Now it's easy to populate that dictionary based on the incoming dictionary.
Upvotes: 1