zoukankan      html  css  js  c++  java
  • App开发流程之数据持久化和编译静态链接库

    先记录数据持久化。

    iOS客户端提供的常用数据持久化方案:NSUserDefaults代表的用户设置,NSKeydArchiver代表的归档,plist文件存储,SQLite数据库(包括上层使用的Core Data,FMDB)。

    每种方案都有各自的应用场景和范围,不能一概而论。不过可以大致以数据储存量和复杂度来区别。

    除了以上提到的方案,再记录一种方案:LevelDB代表的键值对数据库。

     

    NSUserDefaults常用方法:

    1.可以使用标准用户设置[NSUserDefaults standardUserDefaults],也可以通过init相关方法初始化新的用户设置

    2.像使用字典一样获取、设置、移除键值对

    3.synchronize方法已经不建议使用

     

    Plist文件存储:

    1.代码读取应用内已经存在的plist文件,得到一个字典

        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"plist"];

        NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];

    2.修改数据后,保存或者创建plist文件

        [dic writeToFile:filePath atomically:YES];

     

    NSKeydArchiver和NSKeyedUnarchiver:

    1.归档有一个类方法:+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;

       解档有一个类方法:+ (nullable id)unarchiveObjectWithFile:(NSString *)path;

     可以直接对某一个对象进行归档和解档。

    2.但如果需要对多个键值对进行操作,建议使用如下方法:

    + (void)archiveDataWithDictionary:(NSDictionary *)dic filename:(NSString*)filename archiveSuccessBlock:(archiveSuccessBlock)archiveSuccessBlock
    {
        NSString *fullPath = [self getAppArchivedFileFullPathWithName:filename];
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSMutableData *data = [NSMutableData data];
            NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
            
            NSArray *keyArray = [NSArray arrayWithArray:[dic allKeys]];
            [archiver encodeObject:keyArray forKey:filename];
            
            for (NSString *key in keyArray) {
                NSObject *object = [dic objectForKey:key];
                [archiver encodeObject:object forKey:key];
            }
            
            [archiver finishEncoding];
            [data writeToFile:fullPath atomically:YES];
            
            if (archiveSuccessBlock) {
                archiveSuccessBlock();
            }
        });
    }
    
    + (NSDictionary *)unarchiveDataWithFilename:(NSString *)filename
    {
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        
        NSData *data = [[NSData alloc] initWithContentsOfFile:[self getAppArchivedFileFullPathWithName:filename]];
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        
        NSArray *keyArray = [NSArray arrayWithArray:[unarchiver decodeObjectForKey:filename]];
        
        for (NSString *key in keyArray) {
            NSObject *object = [unarchiver decodeObjectForKey:key];
            [dic setObject:object forKey:key];
        }
        
        [unarchiver finishDecoding];
    
        return dic;
    }

    归档的initForWritingWithMutableData和finishEncoding,解档的initForReadingWithData和finishDecoding需要成对出现。

     

    SQLite数据库:

    只要使用过SQL Server和MySQL之类的关系型数据库,就可以轻松使用,只是底层的sql语言不太人性化,所以普遍采用了上层的Core Data或者FMDB类库。

     

    文件操作:

    首先关注方法:FOUNDATION_EXPORT NSArray<NSString *> *NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);第一个枚举参数表示文件目录,第二个表示范围域,第三个参数表示是否补充完整的相对路径

    1.得到当前用户的doc文件根目录:

      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

        NSString *rootPath = paths[0];

    2.补充子文件路径

        NSString *fullPath = [rootPath stringByAppendingPathComponent:filename];

    3.文件操作,主要使用[NSFileManager defaultManager]单例对象 

    + (void)createArchivedRootFile
    {
        NSString *rootPath = [self getAppArchivedFilesRootPath];
        
        if (![[NSFileManager defaultManager] fileExistsAtPath:rootPath]) {
            [[NSFileManager defaultManager] createDirectoryAtPath:rootPath withIntermediateDirectories:YES attributes:nil error:nil];
        }
    }
    
    + (void)clearArchivedFileWithName:(NSString *)filename
    {
        NSString *rootPath = [self getAppArchivedFilesRootPath];
        NSString *fullPath = [rootPath stringByAppendingPathComponent:filename];
        
        if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
            [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];
        }
    }

    除了以上记录方案,再记录一下使用键值对数据库LevelDB的经历。

    当数据量并不是很大,但是又需要数据库存储和操作时候,键值对数据库是首选。源自Google的LevelDB是其中的明星。

    之前遇到客户端存储省市区地址数据的需求,并当用户选择地址时候读取相关数据。如果每次都完整读取省市区数据,占用内存既大又没有必要,因为用户很可能只会选择一个省下的一个市的一个区。

    如果将省市区数据拆分为若干键值对,并且建立某种链式关系,就可以将数据以键值对分散存储于某个地方,并且快速读取需要数据。

    1.第一层级只有一个键值对,key为固定值,value为全部省的名称数组

    2.第二层级键值对数量为省数量,key为省名称,value为市名称数组

    3.第三层级键值对数量为市数量,key为“省名称.市名称”,value为区名称数组

    4.。。。。。

    如上,数据全部以键值对分散存储于LevelDB中,只要知道key规则和名称,就可以快速取到对应数据,而优秀的IO保证了性能表现。

    这是之前记录的一篇关于LevelDB的文章,可以先参考一下:http://www.cnblogs.com/A-Long-Way-Chris/p/4864573.html

     

    编译静态链接库

    正好以LevelDB为案例。先前往下载C++源代码: https://github.com/google/leveldb

    使用Xcode创建静态链接库

    1.新建项目,选择类型

     

    2.设置项目Build Phases,点击区域左上角加号,选择添加Headers Phase

     

    3.点击加号,添加需要公开暴露的头文件,然后从Project栏拖拽到Public栏

     

     

     4.切换真机和模拟器,分别编译成功后,右键Products目录下的libleveldb.a,在Finder中查看

     

    5.在终端程序中cd到该目录,输入如下指令,即可导出同时支持真机和模拟器运行的静态链接库

    lipo -create Debug-iphoneos/libleveldb.a Debug-iphonesimulator/libleveldb.a -output libleveldb.a 

     

    使用命令行,通过Makefile编译LevelDB的静态链接库

    1.解压下载包后,使用Visual Studio Code之类的文本编辑器打开目录下Makefile

    2.修改Makefile中的CXXFLAGS,添加指令 -fembed-bitcode,保存

     

    3.在终端中,cd到LevelDB目录,输入指令:CXXFLAGS=-miphoneos-version-min=7.0 make PLATFORM=IOS

    表示生成iOS版本的静态链接库,支持最低版本为7.0(该设置保证在模拟器上可以正常运行)。

    如果提示permission denied,则在上述指令前加上sudo,最终为:sudo CXXFLAGS=-miphoneos-version-min=7.0 make PLATFORM=IOS,然后输入密码回车即可。

     

     4.说明一下,如果跳过步骤1和2,最后生成的LevelDB静态链接库不支持bitcode,可以看到体积相差还是比较大的,按需编译

     

    将.a文件和include目录下的头文件加入项目即可正常使用。

    1.如果遇到提示某头文件找不到,请检查项目配置中,Header Search Paths是否有配置缺失

    2.如果使用不支持bitcode的版本,需要在build setting中将enable bitcode设置为NO。该设置对其他类库要求一样

    为了便于使用OC编程,还引入了另一个类库,对LevelDB的代码进行了OC封装,地址:https://github.com/matehat/Objective-LevelDB

    我在base项目中,增加了LevelDBHelper工具类,进一步对调用代码进行了封装,操作更简单安全。

    base项目已更新:git@github.com:ALongWay/base.git

  • 相关阅读:
    《数据结构》第1章:绪论
    《计算机网络》第1章:计算机网络体系结构
    笔记迁移至:语雀
    最大似然估计和最大后验概率
    深度学习之最大似然估计
    k折交叉验证(matlab和python程序实现)
    matlab下打乱数组顺序
    线性回归
    梯度算法的Matlab实现
    梯度下降法
  • 原文地址:https://www.cnblogs.com/ALongWay/p/5884654.html
Copyright © 2011-2022 走看看