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, ), ^{
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
App开发流程之数据持久化和编译静态链接库的更多相关文章
- go 工具链目前[不支持编译 windows 下的动态链接库][1],不过[支持静态链接库][2]
go 工具链目前[不支持编译 windows 下的动态链接库][1],不过[支持静态链接库][2].想要产生dll,可以这样 workaround ,参考 golang [issuse#11058][ ...
- 20个可以帮你简化iOS app开发流程的工具
这里推荐20个可以帮你简化iOS app开发流程的工具.很多开发者都使用过这些工具,涉及原型和设计.编程.测试以及最后的营销,基本上涵盖了整个开发过程. 原型和设计 有了一个很好的创意后,你要做的不是 ...
- iOS开发之工具篇-20个可以帮你简化移动app开发流程的工具
如果想进入移动app开发这个领域,你总能从别的开发者或者网上或者书上找到各种各样的方法和工具,对于新手来说,还没有摸清门路就已经陷入迷茫了.这里推荐20个可以帮你简化app开发流程的工具.很多开发者都 ...
- app开发流程有哪些
app开发流程是需求方和供求方相互协调的过程,一般分为需求分析.功能设计.功能实现.项目测试.上线等几个步骤,下面我们就来一起看看ytkah团队进行app开发各个流程主要做哪些事情,让您对app开发设 ...
- GCC编译过程与动态链接库和静态链接库
1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...
- 【DSP开发】DSP能用VS2010生成的链接库文件吗?
[DSP开发]DSP能用VS2010生成的链接库文件吗? 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:可能这个问题让行家看上去就会莞尔一笑,但是很多 ...
- VS2010编译Boost 1.57 静态链接库
http://www.cnblogs.com/cuish/p/4175491.html 0.前提 Boost库版本 1.57.0 下载地址 http://www.boost.org/users/his ...
- GCC 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- VS2008编译iconv静态链接库
iconv是将一种编码格式转换为还有一种编码格式的开源库,比如能够把Windows环境下通用的ASCii(中文是GB2312)编码转换为国际通用的Unicode编码 iconv最新版本号仅仅支持Min ...
随机推荐
- JAVA和C# 3DES加密解密
最近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的B ...
- VirtualBox Bridged 无线网卡
启动虚拟机后选择右键单击右下角的网络链接图标, 弹出的窗口中选择Bridged Adapter, wlan0 然后选择OK 查看virtual Box主页面中setting中网络的配置是否和刚才一 ...
- 剑指架构师系列-tomcat6通过伪异步实现connector
首先在StandardService中start接收请求的线程,如下: synchronized (connectors) { for (int i = 0; i < connectors.le ...
- Slip.js – 在触摸屏上实现列表的滑动排序功能
Slip.js 是一个很小的 JavaScript 库,用于实现对触摸屏的互动 Swipe 和对元素重新排序列表(Reordering).Slip.js 没有任何的依赖,你可以通过自定义 DOM 事件 ...
- 利用栈实现算术表达式求值(Java语言描述)
利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...
- TreeSet与TreeMap浅解
TreeSet与TreeMap的关系: 1.TreeSet 实际上就是用TreeMap来组织数据的,因为在TreeSet中保存了一个NavigableMap<e,Object>接口实例变量 ...
- Struts 2常用的Ajax标签
Struts 2对Ajax的支持 •Struts 2对Ajax提供了很好的支持 –Struts 2.1提供了基于Dojo的Ajax标签,对Ajax操作进行了进步封装,可以更快捷容易的使用Ajax ...
- 用UltraISO制作支持windows 7的U盘启动盘
用UltraISO制作U盘启动盘,有人写过,我也看过,不过依照网上的那些文章,成功的并不多,经过几次试验,在不同的主板环境下成功概率高的方法应该如下: 1. UltraISO建议9.3以上 2. ...
- Netty学习之客户端创建
一.客户端开发时序图 图片来源:Netty权威指南(第2版) 二.Netty客户端开发步骤 使用Netty进行客户端开发主要有以下几个步骤: 1.用户线程创建Bootstrap Bootstrap b ...
- 演练:使用Xamarin.Forms开发产品介绍性质的应用(VB版)
概述 Xamarin这个使用mono和.net core的跨平台开发框架这几年在不断发展.被微软收购后的Xamarin为个人开发者提供了免费版的Xamarin for Visual Studio,吸引 ...