我创建了一个默认的首选项plist文件,当应用程序启动时,我会注册这些默认值。但我允许用户更改一个设置,除了更改每个设置外,还会更改我已注册的几乎所有设置。基本上,我允许他们改变主题"这几乎改变了所有其他存储设置。当用户选择主题时,不是为每个设置调用setObject:forKey
并手动定义所选主题应该是什么,我想知道为每个主题创建另一个plist文件是否明智。我想我可以简单地覆盖密钥匹配的NSUserDefaults
中存储的值。在这样做的过程中,我还可以更轻松地检测应用程序的设置何时与任何主题相同,或者他们是否已定制主题。我只是检测NSUserDefaults
中存储的值是否等于每个键的每个主题plist中存储的值的值,如果它们中的任何一个不同,我知道它们已经定制它并且没有使用内置主题。如果我不使用plist,我必须将每个存储值与手动定义的值进行比较,从而在两个不同的位置定义该主题的默认值(我在选择主题时设置设置,以及我检查当前设置是否与可用主题的设置相同。
如果这是一个合适的实施,how does one overwrite existing values in
NSUserDefaults using the values stored in a plist
?如果没有,在这种情况下你会推荐什么?
答案 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"];
}