数据存储是程序开发中必然会遇到的一个技术需求。真是因为需求的普遍,对应的相关也琳琅满目,令人眼花缭乱。以iOS客户端开发为例,光是系统提供的数据持续化存储的技术就有归档、keychain、NSUserDefault、plist文件等,加上常规的文档读写、数据库、xml等。如何根据项目的实际需要,选择合适的存储技术,值得我们深思。
本文以Firefly_iOS为例,对使用的相关存储技术和选型理由进行了总结。
正文
Firefly_iOS中,使用的数据存储主要涉及到下面几类:
- 1,keychain
- 2,数据库
- 3,NSUserDefault
一、keychain
使用场景
iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌。苹果自己用keychain来保存Wi-Fi网络密码,VPN凭证等等。它是一个在所有app之外的sqlite数据库。
如果我们手动把自己的私密信息加密,然后通过写文件保存在本地,再从本地取出不仅麻烦,而且私密信息也会随着App的删除而丢失。iOS的Keychain能完美的解决这些问题。并且从iOS 3.0开始,Keychain还支持跨程序分享。这样就极大的方便了用户。省去了很多要记忆密码的烦恼。
基于上述keychain实现的定位,只有那些比较敏感的数据,并且应用被卸载重装后还希望保留的敏感数据,我们才会选择存放到keychain。例如,用户设置手势密码,需要和应用标识绑定,这个应用标识存放在keychain,就非常合适。
使用介绍
Firefly_iOS对于keychain的使用,是基于三方库SAMKeychain的封装。
具体的对外暴露接口如下:
@interface FireflyKeychain : NSObject
/**
* 返回指定服务和用户名的密码值,返回格式为NSString
*
* @param serviceName 服务名
* @param aName 用户名
*
* @return 指定服务名和用户名的密码,不存在返回nil
*/
+ (NSString *)passwordForService:(NSString *)serviceName username:(NSString *)aName;
/**
* 返回指定服务和用户名的密码值,返回格式为NSData
*
* @param serviceName 服务名
* @param aName 用户名
*
* @return 指定服务名和用户名的密码,不存在返回nil
*/
+ (NSData *)passwordDataForService:(NSString *)serviceName username:(NSString *)aName;
/**
* keychain中设置密码
*
* @param password 密码,格式为NSString
* @param serviceName 服务名
* @param aName 用户名
*
* @return 成功YES,否则NO
*/
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName username:(NSString *)aName;
/**
* keychain中设置密码
*
* @param password 密码,格式为NSData
* @param serviceName 服务名
* @param aName 用户名
*
* @return 成功YES,否则NO
*/
+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName username:(NSString *)aName;
/**
* 删除keychain中的密码
*
* @param serviceName 服务名
* @param aName 用户名
*
* @return 成功YES,否则NO
*/
+ (BOOL)deletePasswordForService:(NSString *)serviceName username:(NSString *)aName;
@end
二、数据库
使用场景
iOS客户端数据库的使用场景主要用于缓存数据较大的数据。比如,一些下发的网络json数据。
使用介绍
iOS客户端的数据库基本都是使用系统自带的sqlite数据库。目前使用较多的是fmdb。尽管fmdb已经对于底层sqlite作了一层封装,但是对于一般的客户端应用,fmdb还是显得有点大了。
开源库YTKKeyValueStore基于fmdb作了进一步的封装,对于常规的数据库存储完全够用了。因此,Firefly_iOS目前也主要以YTKKeyValueStore作为数据库使用的底层组件。
主要的暴露接口如下:
@interface YTKKeyValueItem : NSObject
@property (strong, nonatomic) NSString *itemId;
@property (strong, nonatomic) id itemObject;
@property (strong, nonatomic) NSDate *createdTime;
@end
@interface YTKKeyValueStore : NSObject
- (id)initDBWithName:(NSString *)dbName;
- (id)initWithDBWithPath:(NSString *)dbPath;
- (void)createTableWithName:(NSString *)tableName;
- (BOOL)isTableExists:(NSString *)tableName;
- (void)clearTable:(NSString *)tableName;
- (void)dropTable:(NSString *)tableName;
- (void)close;
///************************ Put&Get methods *****************************************
- (void)putObject:(id)object withId:(NSString *)objectId intoTable:(NSString *)tableName;
- (id)getObjectById:(NSString *)objectId fromTable:(NSString *)tableName;
- (YTKKeyValueItem *)getYTKKeyValueItemById:(NSString *)objectId fromTable:(NSString *)tableName;
- (void)putString:(NSString *)string withId:(NSString *)stringId intoTable:(NSString *)tableName;
- (NSString *)getStringById:(NSString *)stringId fromTable:(NSString *)tableName;
- (void)putNumber:(NSNumber *)number withId:(NSString *)numberId intoTable:(NSString *)tableName;
- (NSNumber *)getNumberById:(NSString *)numberId fromTable:(NSString *)tableName;
- (NSArray *)getAllItemsFromTable:(NSString *)tableName;
- (NSUInteger)getCountFromTable:(NSString *)tableName;
- (void)deleteObjectById:(NSString *)objectId fromTable:(NSString *)tableName;
- (void)deleteObjectsByIdArray:(NSArray *)objectIdArray fromTable:(NSString *)tableName;
- (void)deleteObjectsByIdPrefix:(NSString *)objectIdPrefix fromTable:(NSString *)tableName;
@end
三、NSUserDefault
使用场景
NSUserDefaults适合存储轻量级的本地数据,一些简单的数据(NSString类型的)例如密码,网址等,NSUserDefaults肯定是首选。
NSUserDefaults是一个单例,在整个程序中只有一个实例对象,他可以用于数据的永久保存,而且简单实用,这是它可以让数据自由传递的一个前提,也是大家喜欢用它保存简单数据的一个主要原因。
NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL。
使用介绍
如果想要将上述数据类型的数据永久保存到NSUserDefaults中去,只需要简单的操作(一个Value 一个Key ),例如,想要保存一个NSString的对象,代码实现为:
//将NSString 对象存储到 NSUserDefaults 中
NSString *passWord = @"1234567";
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:passWord forKey:@"userPassWord"];
将数据取出也很简单,只需要取出key 对应的值就好了,代码如下:
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *passWord = [ user objectForKey:@"userPassWord"];
Firefly_iOS为了防止以后iOS系统升级可能导致的接口变化,基于系统API作了一层封装,具体的接口如下:
#import <Foundation/Foundation.h>
@interface FireflyUserDefaultsManager : NSObject
/**
将数据保存到userDefault数据库
@param value value
@param key key
*/
+ (void)saveUserDefaultsData:(id )value forKey:(NSString *)key;
/**
根据 key 来获取对应的值
@param key key
@return value
*/
+ (id)loadUserDefaultDataByKey:(NSString *)key;
/**
从userDefault删除key - value
@param key key
*/
+ (void)deleteUserDefaultDataByKey:(NSString *)key;
@end
总结
从个人开发经验来看,上述的几个方法已经可以满足iOS客户端数据持久化的大部分使用场景。为了便于数据的维护性和迁移性,个人不是十分推荐使用plist、xml等文本方式。当然,具体的场景还是要具体看的。
参考:
http://www.cnblogs.com/Jenaral/p/5663096.html
https://my.oschina.net/u/1245365/blog/294449
网友评论