iOS轻量数据存储

在北京实习的几个月里,第一次接触OC。之前有接触iOS,但码代码不是很多,也只是学校的一个小项目,当时还是swift1.0版本。

这次总结的是iOS的轻量级数据存储,如果说你要给你的app存储一些账号密码,一些设置的开关(true false)之类的很小的数据,以供下次读取,建议使用NSUserDefaults类。

先来看一下苹果的官方解释:
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html

The NSUserDefaults class provides a programmatic interface for interacting with the defaults system. The defaults system allows an application to customize its behavior to match a user’s preferences. For example, you can allow users to determine what units of measurement your application displays or how often documents are automatically saved. Applications record such preferences by assigning values to a set of parameters in a user’s defaults database. The parameters are referred to as defaults since they’re commonly used to determine an application’s default state at startup or the way it acts by default.

At runtime, you use an NSUserDefaults object to read the defaults that your application uses from a user’s defaults database. NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.

The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData. For more details, see Preferences and Settings Programming Guide.

简单来说,OC提供这个类让你的app可以以直接赋值的方式将数据存储到用户的默认数据库里。下次要用到你存储的数据时,直接使用NSUserDefaults对象去读就行了。Synchronize这个方法是把缓存和数据库进行同步。NSUserDefaults 能存的数据类型有:floats, doubles, integers, Booleans, and URLs等。记得NSUserDefaults是一个单例,是线程安全的,在整个程序中只有一个实例对象。

一. 缓存普通数据

  1. 存储:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

[userDefaults  setBool: NO forKey:IMAGES_DISPLAY_KEY];

[userDefaults  setFloat: myFlout forKey:MY_FLOAT];

[userDefaults  setObject:listData forKey:BANNER_IMAGE];

记得再赋值后调用synchronize方法,不然数据不会同步到数据库里。


[userDefaults synchronize];

存储方法除了这三种还有:setInteger:forKey、setDouble:forKey、setURL:forKey 。大家选择相应的方法使用。

2.读取:


NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

_imageDisplayOrNotSwitch.on = [_userDefaults boolForKey:IMAGES_DISPLAY_KEY];

_myFlout = [_userDefaults floatForKey:MY_FLOAT];

NSData* listData = [[NSUserDefaults standardUserDefaults] objectForKey:BANNER_IMAGE];

这样就方便地完成读取了。值得一提的是 IMAGES_DISPLAY_KEY,MY_FLOAT,BANNER_IMAGE这三个key我都存在了另一个文件里,LocalDataKey.h。所以记得import LocalDataKey.h。

LocalDataKey.h 里是这样的


#ifndef LocalDataKey_h

#define LocalDataKey_h

#define BANNER_IMAGE @"BannerImage"

#define IMAGES_DISPLAY_KEY @"ImageDisplayKey"

#define MY_FLOAT @"MyFloat"

如果有其他的想存储的数据,也可以将key存在这个里面,简单方便。值得注意的是要保证每个key的唯一性,不能有重复,不然会出现数据混淆或错误。

还有一点值得说明的是,NSUserDefaults存储的值是immutable的,是不可变的。比如你要存储一个NSMutableArray的array,你需要重新建立一个array:


NSArray * array = [NSArray arrayWithArray:mutableArray];

再将array使用 [user setObject:array forKey:@"blablabla"]; 存数据,别忘了使用synchronise方法同步到数据库。

二. 缓存自定义对象

实际上NSUserDefaults不支持存储自定义对象, 但支持存储NSData,举个我实习时的例子:

BBBanner.h


#import@interface BBBanner : NSObject

@property (retain,nonatomic) NSString *title;

@property (retain,nonatomic) NSString *href;

@property (retain,nonatomic) NSNumber *type;

@property (retain,nonatomic) NSString *src;

@end

很多人看到这里会想不到下一步会做什么,我们需要做的是将BBBanner这个类型变成NSData。这一步叫归档。首先在.h 文件中申明 NSCoding 协议,再 在 .m 中实现 encodeWithCoder 方法和initWithCoder 方法。实现如下:

BBBanner.m:


#import "BBBanner.h"

#define kType @"BannerTypeKey"

#define kSrc @"BannerSrcKey"

#define kTitle @"BannerTitleKey"

#define kHref @"BannerHrefKey"



@implementation BBBanner

- (void)encodeWithCoder:(NSCoder *)aCoder

{

[aCoder encodeObject:_type forKey:kType];

[aCoder encodeObject:_src forKey:kSrc];

[aCoder encodeObject:_title forKey:kTitle];

[aCoder encodeObject:_href forKey:kHref];

}

- (id) initWithCoder:(NSCoder *)aDecoder

{

self = [[BBBanner alloc] init];

self.type = [aDecoder decodeObjectForKey:kType];

self.href = [aDecoder decodeObjectForKey:kHref];

self.title = [aDecoder decodeObjectForKey:kTitle];

self.src = [aDecoder decodeObjectForKey:kSrc];

return self;

}

@end

这样就将BBBanner这个类型转换成NSData了。

接下来我们实现存储:


BBBanner* banner = [[BBBanner alloc] init];

banner.title = @"hi title";

banner.href = @"hi href";

banner.type = 1;

banner.src = @"www.google.com";



//使用archivedDataWithRootObject转换类型

NSData *bannerData = [NSKeyedArchiver archivedDataWithRootObject: banner];

[bannerDataArray addObject:bannerData];

[_userDefaults setObject:bannerData forKey:BANNER_DATA];

[_userDefaults synchronize];

这样就成功的把banner的类型存进NSUserDefaults啦。同样也可以转换一个里面全是banner类型的NSMutableArray。比如:


NSArray* bannerModels = [BBBanner mj_objectArrayWithKeyValuesArray: dic]; //dic是从网络上请求过来的NSDictionary,mj_objectArrayWithKeyValuesArray是一个引用的库里的方法,可以将一个array里的object类型通过dic转换成BBBanner或者是任意一个你自己创建的类型,像上面一样记得归档。 

NSData *listData = [NSKeyedArchiver archivedDataWithRootObject: bannerModels];

实现读取:

NSData* bannerData = [[NSUserDefaults standardUserDefaults] objectForKey:BANNER_DATA];

//使用unarchiveObjectWithData将数据类型转换回去
BBBanner* banner = [NSKeyedUnarchiver unarchiveObjectWithData:bannerData];

过些时间我会考虑加上存储整个包含自定义类型的数组的实现方法,其实大同小异。

三. 有些人会问 存储的数据到底去哪里了?

这个我也是上网搜了其他的文章才大概有点了解。

它存储在应用程序内置的一个plist文件里,这个可以根据路径看到。详见 http://blog.csdn.net/enuola/article/details/7959767

四.其他的有可能用到的方法

containsObject方法。贴上一段小代码:

if([_userDefaults.dictionaryRepresentation.allKeys containsObject:PUSH_NOTIFICATION_KEY])

{

_pushNotifSwitch.on = [_userDefaults boolForKey:PUSH_NOTIFICATION_KEY];

}

else

{

_pushNotifSwitch.on = YES;

}

这个方法是查找是否有无你需要的key,如果没有,你就有可能读取到NULL,然后导致程序crash之类的。还是挺值得注意的一个方法。

大概要说的就这么多。如果有指正,请随意回复。

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,675评论 18 139
  • 看完人民的名义,已经有几天了,总是想写点什么。是呀,反腐的剧情,跌宕的情节,离奇的身世,貌合神离的婚姻,道貌岸然的...
    厉羽悠君阅读 379评论 1 1
  • 随机选了第8集,顺便看了第9集,忘了看第1集了 第一段 姐妹关系不错,芈月因为牵线和秦王相识 第二段 张仪见怀王、...
    i枫丹白露i阅读 700评论 1 1
  • 读《短篇小说写作指南》 桐子 忽然之间,发现电脑里还存着一本去年下载的《短篇小说写作指南》,看书名像是教材之类的性...
    桐子树下阅读 1,281评论 7 17
  • 我有一个梦想 我想拍一部电影,关于旅行的,主人公不是我,但是我会把我这些年旅行的一些经历不经意间加入进去。 主人公...
    逛逛_阅读 296评论 2 2