码迷,mamicode.com
首页 > 移动开发 > 详细

IOS笔记048-数据存储

时间:2015-06-14 13:44:37      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:

?

IOS数据存储的几种方式

? ? ? ? XML属性列表(plist)

? ? ? ??归档 Preference(偏好设置)?

? ? ? ??NSKeyedArchiver归档(NSCoding)

? ? ? ? SQLite3

? ? ? ??Core Data

先来研究一下前三种。

? ? ? ? 每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒。沙盒的结构如下所示:

技术分享技术分享

? ? ? ?应用程序包:(上图中的QQ.app)包含了所有的资源文件和可执行文件。
? ? ? ?Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录。
? ? ? ?tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录。
? ? ? ?Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据。
? ? ? ?Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录。

每个目录的获取方法

? ? ? ? ? ?//?临时目录

? ? ? ? ? ??NSString?*path =?NSTemporaryDirectory();

? ? ? ? ? ??// /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/A8519BA5-FB34-4B31-BB72-3948264AFB37/tmp/

? ? ? ? ? ??//?主目录

? ? ? ? ? ??NSString?*path = NSHomeDirectory();

? ? ? ? ? ??//? /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/E6A8A443-55CA-463B-886C-DAAF69E8F3BC

?? ? ? ? ? ?

? ? ? ? ? ??// Documents?目录,第三个参数为yes显示全路径,为NO时显示位波浪线 “~”

? ? ? ? ? ??NSString?*path1 =?NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,?NSUserDomainMask,?YES)[0];

? ? ? ? ? ??// /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/61B033AA-BBFB-4A3A-AD6E-2E332B78C2ED/Documents

? ? ? ? ? ??NSString?*path1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,?NO)[0];

? ? ? ? ? ??//? ~/Documents

? ? ? ? ? ??// cache?目录

? ? ? ? ? ??NSString?*path2 =NSSearchPathForDirectoriesInDomains(NSCachesDirectory,?NSUserDomainMask,?YES)[0];

? ? ? ? ? ??// /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/1B4923AF-4B1F-4C7A-941E-D3621D7945C3/Library/Caches

? ? ? ? ? ??// PreferencePanes?目录

? ? ? ? ? ??NSString?*path2 =NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask,?YES)[0];

? ? ? ? ? ??// /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/D654173E-DC23-4951-8C28-016878B5246B/Library/PreferencePanes

还有一个特殊的单例对象用来保存用户设置

? ? ? ? ? ??//?默认保存到PreferencePanes目录

? ? ? ? ? ? [[NSUserDefaults?standardUserDefaults]?setObject:@“hah”?forKey:@"1"];

? ? ? ? ? ? [[NSUserDefaults?standardUserDefaults]?setBool:YES?forKey:@“2”];

1、plist文件

? ? ? ? 属性列表是一种XML格式的文件,拓展名为plist

? ? ? ??如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中.

? ? ? ? 保存数据

? ? ? ? ? ??// plist保存数据

? ? ? ? ? ??//?保存用户名、密码、记住密码、自动登录

? ? ? ? ? ??NSMutableDictionary?*dict = [NSMutableDictionarydictionary];

? ? ? ? ? ? [dict?setObject:_userField.text?forKey:@"user"];

? ? ? ? ? ? [dict?setObject:_pwdField.text?forKey:@"pwd"];

? ? ? ? ? ? [dict?setObject:@(_rmbPwdSwitch.on)?forKey:@"rmb"];

? ? ? ? ? ? [dict?setObject:@(_autoLoginSwitch.on)?forKey:@"auto"];

? ? ? ? ? ??//?获取cache路径

? ? ? ? ? ??NSString?*cachePath =?NSSearchPathForDirectoriesInDomains(NSCachesDirectory,?NSUserDomainMask,?YES)[0];

? ? ? ? ? ??//?取得文件的全路径

? ? ? ? ? ??NSString?*filePath = [cachePath?stringByAppendingPathComponent:@"userInfo.plist"];

? ? ? ? ? ??//?写入到文件

? ? ? ? ? ? [dict?writeToFile:filePath?atomically:YES];

?技术分享

技术分享

? ? ? ?读取数据

? ??//?读取plist中数据,显示在textField

? ??//?获取cache路径

? ??NSString?*cachePath =?NSSearchPathForDirectoriesInDomains(NSCachesDirectory,?NSUserDomainMask,?YES)[0];

? ??//?取得文件的全路径

? ??NSString?*filePath = [cachePath?stringByAppendingPathComponent:@"userInfo.plist"];

? ??//?读取字典数据

? ??NSDictionary?*dict = [NSDictionary?dictionaryWithContentsOfFile:filePath];

? ??//?给控件赋值

? ??NSString?*userName = dict[@"user"];

? ??NSString?*pwd? = dict[@"pwd"];

? ??BOOL?rmb =? dict[@"rmb"];

? ??BOOL?autoLogin = dict[@"autoLogin"];

?? ?

? ??_userField.text?= userName;

?? ?

? ??if?(rmb ==?YES)

? ? {

? ? ? ??_pwdField.text?= pwd;

? ? }

?

? ??_rmbPwdSwitch.on?= rmb;

? ??_autoLoginSwitch.on?= autoLogin;

这里目前还有问题,那就是读取出来的bool变量全是YES。等明天研究一下再。

?问题出来了,读取字典中得bool变量时要转换一下

? ??//?给控件赋值

? ??NSString?*userName = dict[@"user"];

? ??NSString?*pwd? = dict[@"pwd"];

? ??BOOL?rmbPwd =? [dict[@"rmb"]?boolValue];?//?要转换一下,不然读取结果不准确

? ??BOOL?login = [dict[@"autoLogin"]?boolValue];

2、Preference 偏好设置

内部实现也是一个plist文件。不过是否系统控制路径和名称。只需写入和读取就行,不用关系细节。

写入数据

? ? ? ? ? ??// preference?偏好设置

? ? ? ? ? ? ?NSUserDefaults?*userDefault = [NSUserDefaults?standardUserDefaults];?//?单例对象

? ? ? ? ? ? [userDefault?setObject:_userField.text?forKey:@"user"];

? ? ? ? ? ? [userDefault?setObject:_pwdField.text?forKey:@"pwd"];

? ? ? ? ? ? [userDefault?setBool:_rmbPwdSwitch.on?forKey:@"rmb"];

? ? ? ? ? ? [userDefault?setBool:_autoLoginSwitch.on?forKey:@"autoLogin"];

?读取数据

? ??//?偏好设置,读取数据,

? ??NSUserDefaults?*userDefault = [NSUserDefaults?standardUserDefaults];

? ??NSString?*name = [userDefault?stringForKey:@"user"];

? ??NSString?*pwd = [userDefault?stringForKey:@"pwd"];

? ??BOOL?rmbPwd = [[userDefault?boolForKey:@“rmb”] boolValue];

? ??BOOL?login = [[userDefault?boolForKey:@“autoLogin”] boolValue];

? ??//?给控件赋值

? ??_userField.text?= name;

? ??if?(rmbPwd ==?YES)

? ? {

? ? ? ??_pwdField.text?= pwd;?//?记住密码才赋值

? ? }

? ??_rmbPwdSwitch.on?= rmbPwd;

? ??_autoLoginSwitch.on?= login;

? ??if?(login) {?//?自动登录

?? ? ? ?

? ? ? ? [self?login:nil];

? ? }

注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入
[defaults synchornize];

?3、NSKeyedArchiver 归档

如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议有2个方法:
? ? ? ??encodeWithCoder:
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量
? ? ? ??initWithCoder:
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。

? ? 1、常见类型

写入常用类型

? ? ? ? ? ??//?归档对象NSKeyedArchiver

? ? ? ? ? ??//?获取路径

? ? ? ? ? ??NSString?*cachePath =?NSSearchPathForDirectoriesInDomains(NSCachesDirectory,?NSUserDomainMask,?YES)[0];

? ? ? ? ? ??//?取得文件的全路径

? ? ? ? ? ??NSString?*filePath = [cachePath?stringByAppendingPathComponent:@"info.data"];

?? ? ? ? ? ?

//? ? ? ? ? ? [NSKeyedArchiver archiveRootObject:_userField.text toFile:filePath];

? ? ? ? ? ??NSArray?*all =?@[_userField.text,_pwdField.text,@(_rmbPwdSwitch.on),@(_autoLoginSwitch.on)];

? ? ? ? ? ? [NSKeyedArchiver?archiveRootObject:all?toFile:filePath];

读取

? ??//?获取路径

? ??NSString?*cachePath =?NSSearchPathForDirectoriesInDomains(NSCachesDirectory,?NSUserDomainMask,?YES)[0];

? ??//?取得文件的全路径

? ??NSString?*filePath = [cachePath?stringByAppendingPathComponent:@"info.data"];

? ??//?归档对象NSKeyedArchiver

//? ? NSString *name =? [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

? ??NSArray?*all = [NSKeyedUnarchiver?unarchiveObjectWithFile:filePath];

? ??NSLog(@"%@",all);

? ? 2、自定义对象

?要读写自定义对象,自定义对象要遵守NSCoding协议,并实现两个方法,一个打包initWithCoder:,一个解包encodeWithCoder:

?以联系人为例

? ??#import?<Foundation/Foundation.h>

?

? ??@interface?SLQContact :?NSObject?<NSCoding>

?

? ??/*姓名*/

? ??@property?(strong,?nonatomic)?NSString?*name;

? ??//?手机号

? ??@property?(strong,?nonatomic)?NSString?*phone;

?

? ? + (instancetype)contactWithName:(NSString?*)name andPhone:(NSString?*)phone;

? ??@end

实现协议方法?

? ??#import?"SLQContact.h"

?

? ??@implementation?SLQContact

?

? ? + (instancetype)contactWithName:(NSString?*)name andPhone:(NSString?*)phone

? ? {

? ? ? ??SLQContact?*contact = [[self?alloc]?init];

? ? ? ? contact.name?= name;

? ? ? ? contact.phone?= phone;

? ? ? ??return? contact;

? ? }

? ??//?解包,按照key找属性

? ? - (void)encodeWithCoder:(NSCoder?*)aCoder

? ? {

? ? ? ? [aCoder?encodeObject:self.name?forKey:@"name"];

? ? ? ? [aCoder?encodeObject:self.phone?forKey:@"phone"];

? ? }

? ??//?打包,就是给属性指定一个key

? ? - (id)initWithCoder:(NSCoder?*)aDecoder

? ? {

? ? ? ??if?(self?= [super?init])

? ? ? ? {

? ? ? ? ? ??self.name?= [aDecoder?decodeObjectForKey:@"name"];

? ? ? ? ? ??self.phone?= [aDecoder?decodeObjectForKey:@"phone"];

? ? ? ? }

? ? ? ??return??self;

? ? }

? ??@end?

然后在联系人控制器中读写归档文件

定义一个宏用来获取文件路径

//?获得归档文件的路径

#define SLQFilePath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"info.data"]

写如归档文件

? ??//?添加按钮,按下后进入添加联系人界面

? ? - (IBAction)addBtn:(id)sender {

? ? ? ??//

? ??//? ? [self performSegueWithIdentifier:@"contactToAdd" sender:nil];

? ? ? ??//?通过代码获取storyboard中得控制器

? ? ? ??UIStoryboard?*story = [UIStoryboard?storyboardWithName:@"Main"?bundle:nil];

? ? ? ??//?获取mainstoryboard中得控制器,以标识符区分

? ? ? ??SLQAddViewController* addVC = [story?instantiateViewControllerWithIdentifier:@"add"];

? ? ? ??// block封装待执行的代码

? ? ? ? addVC.block= ^(SLQContact?*contact){

? ? ? ? ? ??//?更新模型

? ? ? ? ? ? [self.contacts?addObject:contact];

? ? ? ? ? ??//?刷新表格

? ? ? ? ? ? [self.tableView?reloadData];

? ? ? ? ? ??// 3.保存联系人,注意:如果归档数组,底层会遍历数组元素一个一个归档

? ? ? ? ? ? [NSKeyedArchiverarchiveRootObject:self.contactstoFile:SLQFilePath];

? ? ? ? };

? ? ? ??//?跳转到添加联系人界面

? ? ? ? [self.navigationController?pushViewController:addVC?animated:YES];

? ??}?

?读取归档文件,在属性contacts的setter方法中进行读取。

? ??//?重写set方法

? ? - (NSMutableArray *)contacts

? ? {

? ? ? ??if?(_contacts ==?nil)

? ? ? ? {

? ? ? ? ? ??//?读取归档文件

? ? ? ? ? ? _contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:SLQFilePath];

? ? ? ? ? ??if?(_contacts ==?nil) {?//?如果读取的文件为空,初始化数组

? ? ? ? ? ? ? ? ? _contacts = [NSMutableArray array];

? ? ? ? ? ? }

? ? ? ? }

? ? ? ??return?_contacts;

? ? }

?

还有两种存储方式,属于数据库范畴,继续学习。

?

?

IOS笔记048-数据存储

标签:

原文地址:http://www.cnblogs.com/songliquan/p/4574913.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!