//
// PSDefaults.m
// Perforce
//
// Created by Adam Czubernat on 13.12.2013.
// Copyright (c) 2013 Perforce Software, Inc. All rights reserved.
//
#import "PSDefaults.h"
@interface PSDefaults () {
NSString *rootKey;
NSMutableDictionary *root;
NSString *relativeKeyPath;
}
- (NSArray *)properties;
- (NSString *)keyPathForProperty:(NSString *)property;
- (void)load;
- (void)registerObserving;
- (void)unregisterObserving;
@end
@implementation PSDefaults
- (id)init {
self = [super init];
if (self) {
[self load];
[self registerObserving];
}
return self;
}
- (void)dealloc {
[self unregisterObserving];
}
- (void)initDefaults; {
[[NSUserDefaults standardUserDefaults]
setObject:[NSDictionary dictionary] forKey:self.keyPath];
}
- (NSString *)keyPath {
return self.className;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
id value = [change objectForKey:NSKeyValueChangeNewKey];
[root setValue:value forKeyPath:[self keyPathForProperty:keyPath]];
[defaults setObject:root forKey:rootKey];
[defaults synchronize];
}
- (NSArray *)properties {
NSMutableArray *properties = [NSMutableArray array];
unsigned int count;
objc_property_t *propertyList = class_copyPropertyList([self class], &count);
for (unsigned int idx=0; idx<count; idx++) {
const char *cname = property_getName(propertyList[idx]);
NSString *name = [NSString stringWithUTF8String:cname];
[properties addObject:name];
}
free(propertyList);
return properties;
}
- (NSString *)keyPathForProperty:(NSString *)property {
if (relativeKeyPath)
return [relativeKeyPath stringByAppendingFormat:@".%@", property];
return property;
}
- (void)load {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
relativeKeyPath = nil;
rootKey = self.keyPath;
NSRange range = [rootKey rangeOfString:@"."];
if (range.location != NSNotFound) {
relativeKeyPath = [rootKey substringFromIndex:range.location+1];
rootKey = [rootKey substringToIndex:range.location];
}
root = [[defaults objectForKey:rootKey] mutableCopy] ?: [NSMutableDictionary dictionary];
NSMutableDictionary *dictionary = root;
for (NSString *key in [relativeKeyPath componentsSeparatedByString:@"."]) {
id value = [[dictionary objectForKey:key] mutableCopy] ?: [NSMutableDictionary dictionary];
[dictionary setObject:value forKey:key];
dictionary = value;
}
for (NSString *property in [self properties]) {
id value = [root valueForKeyPath:[self keyPathForProperty:property]];
if (value) {
if ([value isKindOfClass:[NSNull class]])
value = nil;
[self setValue:value forKey:property];
}
}
}
- (void)registerObserving {
for (NSString *property in [self properties])
[self addObserver:self forKeyPath:property options:
NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:NULL];
}
- (void)unregisterObserving {
for (NSString *property in [self properties])
[self removeObserver:self forKeyPath:property];
}
@end