2017年8月10日
1.模型类型数组保存 (需要转化成标准类型)
NSArray<HuTrainKindModel *> *modelArray = [HuTrainKindModel mj_objectArrayWithKeyValuesArray:value];
NSArray *dicArray = [HuTrainKindModel mj_keyValuesArrayWithObjectArray:modelArray];
[HuConfigration writeConfigWithKey:key WithValue:dicArray];
效果:
2.模型类字典保存(需要转化成标准类型)
HuTrainDefaultConfigModel *model = [HuTrainDefaultConfigModel mj_objectWithKeyValues: value];
NSDictionary *dic = model.mj_keyValues;
[HuConfigration writeConfigWithKey:key WithValue:dic];
效果:
2017年7月28日
主要好处,可以非常方便实现配置项存取管理。同时实现一定的读取顺序,实现后台配置项优先生效功能,
一.实现基本原理
1.创建5个dic配置 (其中对应的3个文件data.plist jf-info.plist info.plist)
self.rtConfDic //Runtime只在单次运行中有效
self.tempConfDic //temp下次运行的时候才能生效的配置,其实最终也是保存到fileConfDic里面
self.fileConfDic 对应data.plist
self.jfConfDic 对应 jf-info.plist
self.sysConfDic 对应 info.plist
2.基本实现流程
2.1第一步,程序每次启动,先将5个dic配置 初始化(后3个从用对应文件来初始化)。
2.2第二步,调用后台初始化配置接口数据,如果有最新的配置项数据返回,调用如下接口,将其保存到self.fileConfDic数据中
+ (void)writeConfigWithKey:(NSString *)key WithValue:(id)value;
2.3第三步,程序如果退出或切换后台,会直接将fileConfDic的 数据保存到data.plist, 下次也就可以使用了(实现用户数据沙盒化)。
2.3.1.如果用户要使用保存数据,直接调用
+ (id)readConfigWithKey:(NSString *)key;
读取优先级流程
1、rtConfDic 程序单次运行 该接口存入【+ (void)writeRtMemoryWithKey:(NSString *)key WithValue:(id)value; 】
2、fileConfDic data.plist [这样也就保证了,后台返回配置数据优先于本地配置项] 该接口存入【+ (void)writeConfigWithKey:(NSString *)key WithValue:(id)value;】
3、jfConfDic 对应jf-info.plist
4、sysConfDic 对应程序自带的info.plist
tempString = (NSString *)[this.rtConfDic objectForKey:tempKey];
if(tempString != nil)//如果重名,那runtime的配置优先级最高
{
return tempString;
}
tempString = (NSString *)[this.fileConfDic objectForKey:tempKey]; //data.plist
if(tempString != nil)//重名优先级第二高的,可读写配置
{
return tempString;
}
tempString = (NSString *)[this.jfConfDic objectForKey:tempKey];
if(tempString != nil)//重名优先级第二高的,可读写配置
{
return tempString;
}
tempString = (NSString *)[this.sysConfDic objectForKey:tempKey];
if(tempString != nil)//静态配置,优先级最低
{
return tempString;
}
二.实现
1.配置文件相关接口实现
#define singleton_interface(className) \
+ (className *)shared##className;
// @implementation
#define singleton_implementation(className) \
static className *_instance; \
+ (id)allocWithZone:(NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
+ (className *)shared##className \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[self alloc] init]; \
}); \
return _instance; \
}
#import <Foundation/Foundation.h>
@interface HuConfigration : NSObject
{
//SysConfig Area 预先打入info.plist中的静态配制,不作修改
//静态配置
NSMutableDictionary*sysConfDic;
//JF-Config Area 预先打入JF-Info.plist中的静态配制,不作修改
//静态配置
NSMutableDictionary*jfConfDic;
//FileConfig Area 后期可修改的,以内存中的数据为准的配制项,程序结束后写入文件保存 data.plist
//变量名以file开头
NSMutableDictionary*fileConfDic;
//Runtime只在单次运行中有效,不作保存的零时变量
//变量名以Rt开头
NSMutableDictionary*rtConfDic;
//temp下次运行的时候才能生效的配置
NSMutableDictionary*tempConfDic;
//配置文件名称 data.plist
NSString*SysConfigFileName;
BOOL _bIsNeedSaveCfg; //app切换后台是否需要保存,一般fileConfDic都要保存
}
singleton_interface(HuConfigration)
//配置项相关
@property (nonatomic, strong)NSMutableDictionary*sysConfDic;
@property (nonatomic, strong)NSMutableDictionary*jfConfDic;
@property (nonatomic, strong)NSMutableDictionary*fileConfDic;
@property (nonatomic, strong)NSMutableDictionary*rtConfDic;
@property (nonatomic, strong)NSMutableDictionary*tempConfDic;
///////配置项相关操作函数
/**
* @brief 载入配置管理类各数据结构
*/
- (void)loadConfigData;
/**
* @brief 运行中强制立即写入配置文件。该函数保存数据管理类中除temp以外的数据结构到文件。牵扯同步IO操作,请谨慎使用。
*/
- (void)saveFileDic;
/**
* @brief 保存配置管理类各数据结构。程序即将结束时才调用此函数。
* @desc 保存配置的同时,Css实例会被同步释放。保存后请寻找时机点重新loadCss,保证之后使用正常。
*/
- (void)storeConfigData;
- (void)storeConfigDataIfNeed;
/**
* @brief 配置项读取函数
* @param -key配置项的key
* @return 配置项值
* @desc 根据配置项的key读取配置项的值,一般值为NSString类型,不排除有其他类型的可能性。格式参照IOS plist格式。
*/
+ (id)readConfigWithKey:(NSString *)key;
/**
* @brief 配置项写入函数
* @param -key配置项的key
* @param -value配置项的值
* @desc 根据配置项的key和value存入配置项,一般值为NSString类型,不排除有其他类型的可能性。格式参照IOS plist格式。
*/
+ (void)writeConfigWithKey:(NSString *)key WithValue:(id)value;
/**
* @brief 临时配置项写入函数
* @param -key配置项的key
* @param -value配置项的值
* @desc 功能参考writeConfigWithKey。单次运行时有效的临时配置项写入接口。其取值优先级会高于一切,谨慎使用
*/
+ (void)writeRtMemoryWithKey:(NSString *)key WithValue:(id)value;
/**
* @brief 临时配置项写入函数
* @param -key配置项的key
* @param -value配置项的值
* @desc 功能参考writeConfigWithKey。下次启动才起效果的配置项。谨慎使用
*/
+ (void)writeTempMemoryWithKey:(NSString *)key WithValue:(id)value;
/**
* @brief 轻度级配置项读写函数
* @param -key 配置项的key
* @param -value 配置项的值
* @desc 操作文件类是[NSUserDefaults standardUserDefaults]。
*/
+ (id)readUserDefaultWithKey:(NSString *)key;
+ (void)writeUserDefaultWithKey:(NSString *)key WithValue:(id)value;
@end
#import "HuConfigration.h"
@interface HuConfigration(){
}
@property(nonatomic, assign) BOOL bIsNeedSaveCfg; //是否需要保存配置文件
@end
@implementation HuConfigration
@synthesizesysConfDic;
@synthesizejfConfDic;
@synthesizefileConfDic;
@synthesizertConfDic;
@synthesizetempConfDic;
@synthesize bIsNeedSaveCfg = _bIsNeedSaveCfg;
singleton_implementation(HuConfigration)
///////配置项相关操作函数
- (void)loadConfigData{
//首先读入info.plist中的配制
self.sysConfDic = [NSMutableDictionary dictionaryWithDictionary:[[NSBundle mainBundle] infoDictionary]];
//其次载入JF-info.plist中的交付配置项
NSString *filePath = [HuConfigration appPathWithFileName:@"JF-info.plist"];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
// NSString *jfContent = [HuConfigration encryptStringFromFilePath:filePath];
// self.jfConfDic = [NSMutableDictionary dictionaryWithDictionary:[jfContent propertyListFromStringsFileFormat]];
self.jfConfDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
}else{
self.jfConfDic = [[NSMutableDictionary alloc] initWithCapacity:10];
}
//然后根据文件配制的名称,读取永久配制信息。
SysConfigFileName = @"data.plist";
filePath = [HuConfigration dataFilePathWithFileName:SysConfigFileName WithDirType:NSDocumentDirectory];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
self.fileConfDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
}else{
self.fileConfDic = [[NSMutableDictionary alloc] initWithCapacity:10];
}
self.rtConfDic = [[NSMutableDictionary alloc] initWithCapacity:10];
self.tempConfDic = [[NSMutableDictionary alloc] initWithCapacity:5];
}
+ (NSString*)encryptStringFromFilePath:(NSString*)filePath{
NSData *data = [NSData dataWithContentsOfFile:filePath];
if(data == nil)
return nil;
NSUInteger length = [data length];
char * mem = (char*)malloc(length+1);
if(mem == NULL)
return nil;
memcpy(mem,[data bytes],length);
mem[length] = '\0';
NSString * retString = [NSString stringWithCString:mem encoding:NSUTF8StringEncoding];
free(mem);
return retString;
}
- (void)saveFileDic
{
NSMutableDictionary *logInfo = [[NSMutableDictionary alloc] initWithCapacity:2];
NSString *sysConfigFilePath = [HuConfigration dataFilePathWithFileName:SysConfigFileName WithDirType:NSDocumentDirectory];
TRACELOG(@"path=%@",sysConfigFilePath);
if (![fileConfDic writeToFile:sysConfigFilePath atomically:YES]) {
[logInfo setObject:@"文件保存失败" forKey:@"信息"];
[logInfo setObject:@"执行saveFileDic时失败" forKey:@"出错时机"];
[logInfo setObject:sysConfigFilePath forKey:@"路径"];
}
else {
[logInfo setObject:@"文件保存成功" forKey:@"信息"];
[logInfo setObject:sysConfigFilePath forKey:@"文件保存路径"];
}
[logInfo writeToFile: [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"log_info.plist"] atomically:YES];
TRACELOG(@"我是文件路径----%@",[HuConfigration dataFilePathWithFileName:SysConfigFileName WithDirType:NSDocumentDirectory]);
_bIsNeedSaveCfg = NO;
}
- (void)storeConfigDataIfNeed
{
if (_bIsNeedSaveCfg) {
[self storeConfigData];
}
}
- (void)storeConfigData
{
//NSEnumerator *enumerator = [fileConfDic keyEnumerator];
NSString *tempString = nil,*key = nil;
//while ((key = [enumerator nextObject]))
//{
//tempString = (NSString *)[fileConfDic valueForKey:key];
//}
NSEnumerator *enumerator = [tempConfDic keyEnumerator];
while ((key = [enumerator nextObject]))
{
tempString = (NSString *)[tempConfDic valueForKey:key];
[fileConfDic setObject:tempString forKey:key];
}
[self saveFileDic];
}
+ (id)readConfigWithKey:(NSString *)key
{
NSString *tempString;
NSString *tempKey = [self encodeKey:key];
//特殊处理的不通过配置获取的变量
if ([tempKey compare:@"sys-clientver"] == NSOrderedSame)
{
tempString = SYS_CLIENTVER;
return tempString;
}
HuConfigration *this = [HuConfigration sharedHuConfigration];
tempString = (NSString *)[this.rtConfDic objectForKey:tempKey];
if(tempString != nil)//如果重名,那runtime的配置优先级最高
{
return tempString;
}
tempString = (NSString *)[this.fileConfDic objectForKey:tempKey]; //data.plist
if(tempString != nil)//重名优先级第二高的,可读写配置
{
return tempString;
}
tempString = (NSString *)[this.jfConfDic objectForKey:tempKey];
if(tempString != nil)//重名优先级第二高的,可读写配置
{
return tempString;
}
tempString = (NSString *)[this.sysConfDic objectForKey:tempKey];
if(tempString != nil)//静态配置,优先级最低
{
return tempString;
}
return nil;
}
+ (void)writeConfigWithKey:(NSString *)key WithValue:(id)value
{
NSString *tempKey = [self encodeKey:key];
@try {
if(value == nil){
[[HuConfigration sharedHuConfigration].fileConfDic removeObjectForKey:tempKey];
}
else {
[[HuConfigration sharedHuConfigration].fileConfDic setObject:value forKey:tempKey];
}
}
@catch (NSException * e) {
TRACELOG(@"%@",[e name]);
TRACELOG(@"%@",[e reason]);
}
@finally {
}
[HuConfigration sharedHuConfigration].bIsNeedSaveCfg = YES;
}
+ (void)writeRtMemoryWithKey:(NSString *)key WithValue:(id)value
{
NSString *tempKey = [self encodeKey:key];
@try {
if(value == nil){
[[HuConfigration sharedHuConfigration].rtConfDic removeObjectForKey:tempKey];
}
else {
[[HuConfigration sharedHuConfigration].rtConfDic setObject:value forKey:tempKey];
}
}
@catch (NSException * e) {
TRACELOG(@"%@",[e name]);
TRACELOG(@"%@",[e reason]);
}
@finally {
}
}
+ (void)writeTempMemoryWithKey:(NSString *)key WithValue:(id)value
{
NSString *tempKey = [self encodeKey:key];
@try {
if(value == nil){
[[HuConfigration sharedHuConfigration].tempConfDic removeObjectForKey:tempKey];
}
else {
[[HuConfigration sharedHuConfigration].tempConfDic setObject:value forKey:tempKey];
}
}
@catch (NSException * e) {
TRACELOG(@"%@",[e name]);
TRACELOG(@"%@",[e reason]);
}
@finally {
}
[HuConfigration sharedHuConfigration].bIsNeedSaveCfg = YES;
}
+ (id)readUserDefaultWithKey:(NSString *)key
{
if (key) {
@try {
return [[NSUserDefaults standardUserDefaults] objectForKey:key];
} @catch (NSException *e) {
TRACELOG(@"%@",[e name]);
TRACELOG(@"%@",[e reason]);
return @"";
} @finally {
}
}
return nil;
}
+ (void)writeUserDefaultWithKey:(NSString *)key WithValue:(id)value
{
if (key) {
NSUserDefaults *standardUserDefault = [NSUserDefaults standardUserDefaults];
if (value) {
[standardUserDefault setValue:value forKey:key];
}
else {
[standardUserDefault removeObjectForKey:key];
}
[standardUserDefault synchronize];
}
}
#pragma mark - Configration methods
+ (NSString*)encodeKey:(NSString*)key
{
NSString *tempKey;
tempKey = [key stringByReplacingOccurrencesOfString:@"_" withString:@"-"];
return tempKey;
}
@end
2.合适的时候初始化文件,合适的时候,将数据保存到沙盒里
#import “AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//1.初始化data.plist 相关配置文件
[self startConfigureFiles];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
//2.切换到后台保存
[[HuConfigration sharedHuConfigration] storeConfigDataIfNeed];
}
- (void)applicationWillTerminate:(UIApplication *)application {
//2.1. 程序退出的时候,保存配置项到data.plist
[[HuConfigration sharedHuConfigration] saveFileDic];
}
- (void)startConfigureFiles{
[[HuConfigration sharedHuConfigration] loadConfigData];
}
三.具体使用(eg:登录账号配置项操作)【目前暂时先不考虑敏感数据加密,以后扩展】
第一步:登录后保存数据
- (void)loginBtnClick:(UIButton *)btn{
//test save
//………
[HuConfigration writeConfigWithKey:@"loginPhoneNumber" WithValue:_phoneText.text];
}
程序切换后台或关闭,沙盒里面就回创建data.plist文件
第二步,使用(再次登录就回获取沙盒里面的值)
//配置项使用:
_phoneText.text = [HuConfigration readConfigWithKey:@"loginPhoneNumber"];)
四.其他
1.注,配置项也可以是其他类型 ,如数组
存:
NSMutableArray * arrayNew = [NSMutableArray arrayWithCapacity:8];
[HuConfigration writeConfigWithKey:AFFICHE_NOTICE_ARRAY_KEY WithValue:arrayNew];
使用:
NSArray * arrayNoNotice = (NSArray *)[HsConfigration readConfigWithKey:AFFICHE_NOTICE_ARRAY_KEY];
2.注,也将NSUserDefaults 读取接口化,同时添加try catch保护,避免程序奔溃 【建议少用,用上面的配置项机制就可以】
/**
* @brief 轻度级配置项读写函数
* @param -key 配置项的key
* @param -value 配置项的值
* @desc 操作文件类是[NSUserDefaults standardUserDefaults]。
*/
+ (id)readUserDefaultWithKey:(NSString *)key;
+ (void)writeUserDefaultWithKey:(NSString *)key WithValue:(id)value;
如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。