序言:最近項目開發(fā)有一需求:本公司開發(fā)的是智能控制系統(tǒng),每臺機器初始設定時,需要用戶設定各個參數(shù)的值,由于頁面參數(shù)眾多,用戶對一臺設定好參數(shù)后,可能需要對其他的機器也所有參數(shù)設定同樣的值。此時需求就出來:每當用戶設定好參數(shù)后,點擊頁面的保存按鈕后,就會保存該參數(shù)模板到本地。當對其他機器設定是,頁面會出現(xiàn)使用上次設置按鈕,當用戶點擊此按鈕時,就會將本地保存的所有有效的參數(shù)值按順序進行下發(fā)設定(有效值:每個參數(shù)都會有默認值,一般默認值都是該類型的最大值,沒有意義)。
分析:
初期,我的開發(fā)思路是這樣的:
-
1. 對應每個頁面建一個
model,然后在model中按頁面參數(shù)順序定義所對應的參數(shù)值assign類型的存儲屬性。初始化時會對所有的參數(shù)值初始化一個默認值,即最大值; -
2. 當用戶點擊保存時,會取出當前頁面所有的參數(shù)值,會按順序?qū)⒂行У膮?shù)值寫入
model的存儲屬性中(默認值就不寫入); -
3. 當用戶點擊
使用上次設置時,會取出該該model的屬性值,按順序下發(fā)有效的參數(shù)值。
弊端:對應每個頁面都需要創(chuàng)建一個model,對應多個頁面就需要多個model;然后每個Model需要定義多個存儲屬性以一一對應頁面的參數(shù)。最后可能需要第三方的框架(MJExtension),將每個模型對象轉(zhuǎn)換成NSString對象,繼而將該對象存儲到沙盒。還要從沙盒中去取該NSString對象,然后轉(zhuǎn)成model對象。
model的.m文件中
- (void)save {
//將初始化模型(InitiatorModel)轉(zhuǎn)為json字符串
NSString *json = [self mj_JSONString];
//寫入用戶偏好設置數(shù)據(jù)庫
[[NSUserDefaults standardUserDefaults] setObject:json forKey:ACTIVE_REACTIVE_MODEL_KEY];
}
+ (instancetype)activeReactiveModel {
//從用戶偏好設置數(shù)據(jù)庫取json字符串
NSString *json = [[NSUserDefaults standardUserDefaults] objectForKey:ACTIVE_REACTIVE_MODEL_KEY];
if (!json) {
return nil;
}
//通過json字符串轉(zhuǎn)為初始化模型(InitialModel)
ActiveReactiveModel *activeReactiveModel = [ActiveReactiveModel mj_objectWithKeyValues:json];
return activeReactiveModel;
}
開發(fā)完成之后,基本功能都可以實現(xiàn),但是發(fā)現(xiàn)擴展性不好,每個頁面都對應一個model。后來和同事溝通交流,一同事說有更好的實現(xiàn)方式,利用NSKeyedArchiver實現(xiàn)對象的歸檔。但是有個前提,一般對象都是系統(tǒng)Foundation框架下的類的對象都可以實現(xiàn)。究其根由,Foundation框架下的類都是遵從NSCoding協(xié)議??聪绿O果開發(fā)文檔。

所有在自己定義的模型model中遵從NSCoding協(xié)議,然后實現(xiàn)該協(xié)議的兩個協(xié)議方法。
model文件SARegister類
SARegister.h文件:
#import <Foundation/Foundation.h>
@interface SARegister : NSObject<NSCoding>
/// 寄存器地址
@property (nonatomic, assign) NSUInteger address;
/// 寄存器個數(shù)(從文件中讀取時確定)
@property (nonatomic, assign, readonly) NSUInteger length;
/// 讀取上來的 rawValue
@property (nonatomic, strong) NSData *valueData;
/// 計算屬性
@property (nonatomic, assign) NSInteger value;
@property (nonatomic, strong) NSString *utf8Value;
/// 最近一次跟新 value 的時間
@property (nonatomic, strong) NSDate *lastDate;
@property (nonatomic, strong) NSString *name;
/** 通過registerId來獲取唯一的寄存器 */
@property (nonatomic, strong) NSString *registerId;
@end
SARegister.m文件:
#import "SARegister.h"
@implementation SARegister
...
//省略代碼
...
#pragma mark - NSCoding
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.address = [aDecoder decodeIntegerForKey:@"address"];
self.valueData = [aDecoder decodeObjectForKey:@"valueData"];
self.lastDate = [aDecoder decodeObjectForKey:@"lastDate"];
self.name = [aDecoder decodeObjectForKey:@"name"];
self.registerId = [aDecoder decodeObjectForKey:@"registerId"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeInteger:self.address forKey:@"address"];
[aCoder encodeObject:self.valueData forKey:@"valueData"];
[aCoder encodeObject:self.lastDate forKey:@"lastDate"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.registerId forKey:@"registerId"];
}
@end
頁面的ViewController.m文件中:具體展示保存和取出model數(shù)組
//文件保存路徑:Library/Application Support
- (NSString *)archivePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *documentsPath = @"";
if (paths.count > 0) {
documentsPath = paths.firstObject;
if (! [[NSFileManager defaultManager] fileExistsAtPath:documentsPath]) {
NSError *error;
if(![[NSFileManager defaultManager] createDirectoryAtPath:documentsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Failed to create directory. error: %@",error);
}
}
}
return documentsPath;
}
//保存參數(shù)模板(model數(shù)組)
- (void)saveModel{
[[NSFileManager defaultManager] changeCurrentDirectoryPath:self.archivePath];
BOOL succes = [NSKeyedArchiver archiveRootObject:self.saRegisters toFile:self.titleName];
if (succes) {
[Utility showSuccessToastStatus:NSLocalizedString(@"保存成功", @"保存成功")];
} else {
[Utility showErrorToastStatus:NSLocalizedString(@"數(shù)據(jù)同步失敗"", @"數(shù)據(jù)同步失敗")];
}
}
//取出model數(shù)組
- (NSArray<SAMenuItem *>*)useTemplate {
if (self.canSave) {
NSString *path = [self.archivePath stringByAppendingPathComponent:self.titleName];
NSArray<SAMenuItem *> *archiver = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
return archiver;
}
return nil;
}
注意:如果定義的
model中的某個屬性同樣也是自己定義的一個類的對象,那么該類也是要遵從NSCoding協(xié)議,然后實現(xiàn)兩個協(xié)議方法。
- (instancetype)initWithCoder:(NSCoder *)aDecoder;
- (void)encodeWithCoder:(NSCoder *)aCoder;