|
// |
|
// MTLModel+MTLNSUbiquitousKeyValueStore.m |
|
// |
|
// Created by Charles Etzel on 11/11/13. |
|
// Copyright (c) 2013 Charles Etzel. All rights reserved. |
|
// |
|
|
|
#import <objc/runtime.h> |
|
#import "MTLModel+MTLNSUbiquitousKeyValueStore.h" |
|
#import "MTLModel+NSCoding.h" |
|
|
|
#define MTLMODEL_UKVS_CLASSNAME_KEY @"__MTLModel_NSUbiquitousKeyValueStore_className__" |
|
|
|
@implementation MTLModel (MTLNSUbiquitousKeyValueStore) |
|
|
|
- (instancetype)initWithUbiquitousKeyValueStoreDictionary:(NSDictionary *)dictionary |
|
{ |
|
if (self = [super init]) { |
|
for (NSString *key in self.class.propertyKeys) { |
|
id val = dictionary[key]; |
|
|
|
if (!val || val == [NSNull null] || [val isEqual:[NSNull null]]) { |
|
continue; |
|
} |
|
|
|
id finalVal = [self __resolvedUbiquitousKeyValueStoreValueForValue:val]; |
|
[self setValue:finalVal forKey:key]; |
|
} |
|
} |
|
return self; |
|
} |
|
|
|
- (id)__resolvedUbiquitousKeyValueStoreValueForValue:(id)val |
|
{ |
|
if ([val isKindOfClass:[NSDictionary class]]) { |
|
|
|
if ([val objectForKey:MTLMODEL_UKVS_CLASSNAME_KEY]) { |
|
|
|
Class cls = NSClassFromString([val objectForKey:MTLMODEL_UKVS_CLASSNAME_KEY]); |
|
if ([[cls class] isSubclassOfClass:[MTLModel class]]) { |
|
id object = [[cls alloc] initWithUbiquitousKeyValueStoreDictionary:val]; |
|
return object; |
|
} else { |
|
return val; |
|
} |
|
|
|
} else { |
|
|
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary]; |
|
for (NSString *key in val) { |
|
id resolvedVal = [self __resolvedUbiquitousKeyValueStoreValueForValue:[val valueForKey:key]]; |
|
[dict setValue:resolvedVal forKey:key]; |
|
} |
|
return dict; |
|
} |
|
|
|
} else if ([val isKindOfClass:[NSArray class]]) { |
|
|
|
NSMutableArray *array = [NSMutableArray array]; |
|
for (id arrVal in val) { |
|
id object = [self __resolvedUbiquitousKeyValueStoreValueForValue:arrVal]; |
|
[array addObject:object]; |
|
} |
|
return array; |
|
|
|
} else { |
|
|
|
return val; |
|
|
|
} |
|
} |
|
|
|
- (NSDictionary *)ubiquitousKeyValueStoreDictionaryRepresentation |
|
{ |
|
NSMutableDictionary *returnDict = [NSMutableDictionary dictionary]; |
|
NSDictionary *encodingBehaviors = self.class.encodingBehaviorsByPropertyKey; |
|
[self.dictionaryValue enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { |
|
// Skip nil values. |
|
if ([value isEqual:NSNull.null]) return; |
|
|
|
switch ([encodingBehaviors[key] unsignedIntegerValue]) { |
|
// This will also match a nil behavior. |
|
case MTLModelEncodingBehaviorExcluded: |
|
break; |
|
|
|
case MTLModelEncodingBehaviorUnconditional: |
|
case MTLModelEncodingBehaviorConditional: { |
|
id transformedVal = [self __transformedUbiquitousKeyValueStoreValueForValue:value]; |
|
[returnDict setValue:transformedVal forKey:key]; |
|
} |
|
break; |
|
|
|
default: |
|
NSAssert(NO, @"Unrecognized encoding behavior %@ for key \"%@\"", encodingBehaviors[key], key); |
|
} |
|
}]; |
|
|
|
[returnDict setValue:NSStringFromClass([self class]) forKey:MTLMODEL_UKVS_CLASSNAME_KEY]; |
|
|
|
return returnDict; |
|
} |
|
|
|
- (id)__transformedUbiquitousKeyValueStoreValueForValue:(id)val |
|
{ |
|
if ([val respondsToSelector:@selector(ubiquitousKeyValueStoreDictionaryRepresentation)]) { |
|
|
|
return [val ubiquitousKeyValueStoreDictionaryRepresentation]; |
|
|
|
} else if ([val isKindOfClass:[NSDictionary class]]) { |
|
|
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary]; |
|
for (NSString *key in val) { |
|
id transformedVal = [self __transformedUbiquitousKeyValueStoreValueForValue:[val valueForKey:key]]; |
|
[dict setValue:transformedVal forKey:key]; |
|
} |
|
return dict; |
|
|
|
} else if ([val isKindOfClass:[NSArray class]]) { |
|
|
|
NSMutableArray *array = [NSMutableArray array]; |
|
for (id obj in val) { |
|
if ([obj respondsToSelector:@selector(ubiquitousKeyValueStoreDictionaryRepresentation)]) { |
|
[array addObject:[obj ubiquitousKeyValueStoreDictionaryRepresentation]]; |
|
} else { |
|
[array addObject:obj]; |
|
} |
|
} |
|
return array; |
|
|
|
} else { |
|
|
|
return val; |
|
|
|
} |
|
} |
|
|
|
- (void)persistToUbiquitousKeyValueStoreForKey:(NSString *)key |
|
{ |
|
if (!key) { |
|
return; |
|
} |
|
|
|
[[NSUbiquitousKeyValueStore defaultStore] setDictionary:[self ubiquitousKeyValueStoreDictionaryRepresentation] forKey:key]; |
|
} |
|
|
|
@end |