美文网首页
iOS plist 文件管理

iOS plist 文件管理

作者: iOS坚持者 | 来源:发表于2018-08-13 13:02 被阅读140次

最近在项目中本地化存储的时候用NSUserDefaults来做本地化储存,随着项目越来越大,需要存入的数据也越来越多,比如各种判断条件,是否第一次登录,是否第一次安装等等,这些条件多了,觉得不太好管理,就想着统一用一个 plist 文件来管理这些。

/**
操作plist

 @param pathBlock  设置路径
 @param handleBlock 数据操作
 @return 这个闭包是用来存储更新到本地,如果这是查询不需要更新本地,可以不调用这个返回值
 */
-(void(^)(void))nativeConfigOperate:
(NSArray<NSString *>*(^)(void))pathBlock
handle:(void(^)(NSMutableDictionary *valueLastDic, id value))handleBlock;

基于高阶函数的启发设计了这么一个类出来管理本地的 plist 文件,
这个方法是线程安全的,即使在多线程中操作访问也是没问题。
pathBlock:设置 plist 文件中的路径,如下图查找BaseConfig中的key,则返回@[@"BaseConfig",@"key"]

@2x.png

handleBlock:返回查询到的数据,
如果路径不对:

  • A:在最后一个路径之前就已经有路径不存在,那么返回valueLastDic,value两个参数都是 nil,并且最后writeToFile 依然是之前已经存在的 plist 文件,plist 文件不会改变。
  • B:如果是之前的路径没有问题,路径都是存在的,只是最后一个路径不存在,那么返回的valueLastDic为查询路径的上一个dic,那工程里面的 InfoConfig.plist 举例如:@[@"c"],那么valueLastDic就是整个plist字典,如果:@[@"BaseConfig",@"aa"],那么valueLastDic就是路径 BaseConfig 下的字典。 增删改这些字典最后writeToFile是操作过的数据.
    返回值 block:调用这个闭包用来执行writeToFile存储更新到本地,如果这是查询不需要更新本地,可以不执行这个block。
    关于嵌套的问题,如果是两个嵌套返回的valueLastDic是兄弟关系的话,最后存储的数据都是正确的,如果是父子层级的以最后调用返回值 block的结果为准,会存在覆盖前值的问题。

最后贴上实现代码。点我下载,喜欢的点个赞

-(void(^)(void))nativeConfigOperate:(NSArray<NSString *>*(^)(void))pathBlock handle:(void(^)(NSMutableDictionary *lastDic, id value))handleBlock
{
    NSAssert(pathBlock != nil, @"路径不能为空");

    dispatch_semaphore_wait(signal, overTime);
    
    ///沙盒 plist 路径,不要放在工程目录下,没有权限去修改。
    NSString *infoplistPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"config/InfoConfig.plist"];
    
    NSArray <NSString *>* keypathArr = pathBlock();
    
    
    if (keypathArr.count == 0) {

        return ^{ };
    }
    
    //plist 对象
    NSMutableDictionary *bigDic = [NSMutableDictionary dictionaryWithContentsOfFile:infoplistPath];
    NSLog(@"lastDic 初始化===%@",bigDic);
    //最后一个 key 所在的 dictionary,暴露给其他调用类,可以用来增删改查操作
    NSMutableDictionary *lastDic = bigDic;
    id lastData = nil;
    
    for (int i=0; i<keypathArr.count; i++) {
        if (i==keypathArr.count-1) {
            
            //根据keypathArr路径查询最后一个 key 对应的数据
            lastData = lastDic[keypathArr[i]];

            break;
        }
        lastDic = lastDic[keypathArr[i]];
    }
    
    
    
    WeakObj(keypathArr);
    WeakObj(infoplistPath);
    WeakObj(lastDic);
    WeakObj(bigDic);
        
    void(^handleFinishBlock)(void) = ^{
        
        /*
         optimize:
         应该采用链表结构设计,
         */
        #warning 最结束处一定要调用线程解锁
        //在返回 block 的时候一定要解锁,否则会阻塞线程
        dispatch_semaphore_wait(signal, overTime);
        
        //用 strong 修饰防止weak 修饰的对象释放,而 block 对其内部创建的对象并不会再一次的强引用
        StrongObj(keypathArr_W);
        StrongObj(infoplistPath_W);
        StrongObj(lastDic_W);
        StrongObj(bigDic_W);
        
     
        if (keypathArr_WS.count == 1) {//第一层
            bigDic_WS = lastDic_WS;
        }else {//第二层及以上
            
            NSMutableDictionary *tempDic = bigDic_WS;
            NSInteger count = keypathArr_WS.count-1;
            
            //for 遍历,后期我将尝试用节点的方式来设计算法
            for (int i=0; i<count; i++) {
                
                if (i == count-1) {
                    if (i == 0) {
         
                        //最终遍历会执行到这里结束
                        [bigDic_WS setValue:lastDic_WS forKey:keypathArr_WS[i]];

                        break;
                    }
                    [tempDic setValue:lastDic_WS forKey:keypathArr_WS[i]];
                    
                    count = i;
                    i = -1;
                    lastDic_WS = tempDic;

                    tempDic = bigDic_WS;
                    
                    continue;
                }
                
                tempDic = tempDic[keypathArr_WS[i]];

            }
        }
        /*
         路径数组中包含不存在的路径
         1、最后一个 key 不存在,则依然会返回正确的 lastDic ,只是返回的 value 为空而已。
         2、之前的 key 不存在,那么存入的依然是之前本地已经存在的数据,不会改变
         */
        NSLog(@"bigDic_WSKVC 赋值后===%@",bigDic_WS);
        BOOL storage = [bigDic_WS writeToFile:infoplistPath_WS atomically:YES];
        NSLog(@"储存==%@---%@",storage?@"成功":@"失败",keypathArr);
        
        #warning 最结束处一定要调用线程解锁
        //线程解锁
        dispatch_semaphore_signal(signal);

    };
    
    handleBlock(lastDic, lastDic[keypathArr[keypathArr.count-1]]);
    dispatch_semaphore_signal(signal);
    return handleFinishBlock;
}

最后说一句,链式点语法调用爽爆了。

相关文章

网友评论

      本文标题:iOS plist 文件管理

      本文链接:https://www.haomeiwen.com/subject/ymnybftx.html