通过plist覆盖NSUserDefaults值

时间:2014-08-16 19:25:16

标签: ios swift plist nsuserdefaults

我创建了一个默认的首选项plist文件,当应用程序启动时,我会注册这些默认值。但我允许用户更改一个设置,除了更改每个设置外,还会更改我已注册的几乎所有设置。基本上,我允许他们改变主题"这几乎改变了所有其他存储设置。当用户选择主题时,不是为每个设置调用setObject:forKey并手动定义所选主题应该是什么,我想知道为每个主题创建另一个plist文件是否明智。我想我可以简单地覆盖密钥匹配的NSUserDefaults中存储的值。在这样做的过程中,我还可以更轻松地检测应用程序的设置何时与任何主题相同,或者他们是否已定制主题。我只是检测NSUserDefaults中存储的值是否等于每个键的每个主题plist中存储的值的值,如果它们中的任何一个不同,我知道它们已经定制它并且没有使用内置主题。如果我不使用plist,我必须将每个存储值与手动定义的值进行比较,从而在两个不同的位置定义该主题的默认值(我在选择主题时设置设置,以及我检查当前设置是否与可用主题的设置相同。

如果这是一个合适的实施,how does one overwrite existing values in NSUserDefaults using the values stored in a plist?如果没有,在这种情况下你会推荐什么?

1 个答案:

答案 0 :(得分:0)

请参阅,设置是应用程序中的一个概念(存储和使用UI文本设置),最好设计一个抽象的实际实现(持久存在于.plists,数据库等等)。

所有这些单独的值都由一个概念组合在一起,因此可以由项目中的类表示。这堂课"包装"与概念相关的实施细节。此逻辑与程序的其他部分隔离,当您需要更改它时,您的更改仅限于一个实体,因此每次更改都不太可能破坏您的其余代码。

这个类可以这样实现:

 
/////////////
// TextSettings.h

#import <Foundation/Foundation.h>

@interface TextSettings : NSObject <NSCoding>

@property (nonatomic, strong) UIColor *mainColor;
@property (nonatomic, copy) UIFont *font;

+ (instancetype)defaultTextSettings;

@end

/////////////
// TextSettings.m

@implementation TextSettings

+ (instancetype)defaultTextSettings
{
    TextSettings *textSettings = [[TextSettings alloc] init];
    textSettings.font = [UIFont systemFontOfSize:14.0f];
    textSettings.mainColor = [UIColor whiteColor];
    return textSettings;
}

#pragma mark - NSCoding

// Read more about NSCoding on: http://nshipster.com/nscoding/

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        _font = [aDecoder decodeObjectForKey:@"_font"];
        _mainColor = [aDecoder decodeObjectForKey:@"_mainColor"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:self.font forKey:@"_font"];
    [aCoder encodeObject:self.mainColor forKey:@"_mainColor"];
}

#pragma mark - Equality

- (BOOL)isEqual:(id)object
{
    if (object == nil) {
        return NO;
    }

    if ([object isKindOfClass:[self class]] == NO) {
        return NO;
    }

    TextSettings *otherTextSettings = object;

    return [self.font isEqual:otherTextSettings.font] && [self.mainColor isEqual:otherTextSettings.mainColor];
}

// You must override -hash if you override -isEqual
- (NSUInteger)hash
{
    return self.class.hash ^ self.font.hash ^ self.mainColor.hash;
}

@end

当你有这样一个对象时,你可以:

  • 轻松测试他们的平等
  • 轻松归档和取消归档(序列化和反序列化)

平等测试

 
// TextSettings *myTextSettings
if ([myTextSettings isEqual:[TextSettings defaultTextSettings]]) {
    // User didn't change the textSettings...
} 
else {
    // User changed the textSettings!
}

<强>序列化/反序列化

 
// In a controller responsible for displaying something according to textSettings.
// textSettings (self.textSettings) is a @property in this controller.
- (void)saveCurrentTextSettings 
{
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.textSettings];
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"currentTextSettings"];
}

- (void)loadTextSettings
{
    NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:@"currentTextSettings"];
    self.textSettings = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}

那就是它。

如果要向TextSettings添加新字段,必须(1)将它们声明为@properties,(2)将检查添加到-isEqual:-hash实现,以及(3)将取消归档/归档代码添加到-encodeWithCoder-initWithCoder

那太多了!你可能会说,但我说不 - 这几乎不是一种矫枉过正。绝对比在NSUserDefaults中搜索和比较单个值更好。


<强> UPD:

将其用作普通设置:

 
// Called when user chooses new value
- (void)userDidChooseFont:(UIFont *)font
{
    self.textSettings.font = font;
    [self saveTextSettings];
}

- (void)saveTextSettings
{
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.textSettings];
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"textSettings"];
}
相关问题