IOS配置文件常用相关机制实现(沙盒里创建data.plist文件实现)

2017年8月10日
1.模型类型数组保存 (需要转化成标准类型)

NSArray<HuTrainKindModel *> *modelArray = [HuTrainKindModel mj_objectArrayWithKeyValuesArray:value];
            NSArray *dicArray = [HuTrainKindModel mj_keyValuesArrayWithObjectArray:modelArray];
            [HuConfigration writeConfigWithKey:key WithValue:dicArray];

效果:


image.png

2.模型类字典保存(需要转化成标准类型)

HuTrainDefaultConfigModel *model = [HuTrainDefaultConfigModel mj_objectWithKeyValues: value];
            NSDictionary *dic = model.mj_keyValues;
            [HuConfigration writeConfigWithKey:key WithValue:dic];

效果:


image.png

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文件

image.png

第二步,使用(再次登录就回获取沙盒里面的值)

//配置项使用:
    _phoneText.text = [HuConfigration readConfigWithKey:@"loginPhoneNumber"];)
image.png

四.其他
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;

如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,084评论 1 32
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,813评论 0 5
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,169评论 0 9
  • 我亲爱的老婊 你在我心里是一个支柱,不同于家人,不同于男友,你们三个是并重的。 看到你最近的状态很好,每天都有在跑...
    申十二阅读 406评论 2 0
  • 课题目标知识目标:1.了解眼睛的基本构造及近视的成因及表现特征。2.知道如何预防近视和掌握正确的做眼保健操的方法。...
    稳稳的幸福_c9df阅读 102评论 0 0