IOS笔记048-数据存储
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时显示位波浪线 “~”
];
// /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/61B033AA-BBFB-4A3A-AD6E-2E332B78C2ED/Documents
];
// ~/Documents
// cache 目录
];
// /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/1B4923AF-4B1F-4C7A-941E-D3621D7945C3/Library/Caches
// PreferencePanes 目录
];
// /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 *filePath = [cachePath stringByAppendingPathComponent:@"userInfo.plist"];
// 写入到文件
[dict writeToFile:filePath atomically:YES];


读取数据
// 读取plist中数据,显示在textField中
// 获取cache路径
];
// 取得文件的全路径
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 *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 *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)[] stringByAppendingPathComponent:@"info.data"]
写如归档文件
// 添加按钮,按下后进入添加联系人界面
- (IBAction)addBtn:(id)sender {
//
// [self performSegueWithIdentifier:@"contactToAdd" sender:nil];
// 通过代码获取storyboard中得控制器
UIStoryboard *story = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 获取main。storyboard中得控制器,以标识符区分
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-数据存储的更多相关文章
- 李洪强iOS开发之数据存储
李洪强iOS开发之数据存储 iOS应用数据存储的常用方式 1.lXML属性列表(plist)归档 2.lPreference(偏好设置) 3.lNSKeyedArchiver归档(NSCoding) ...
- ios中常见数据存储方式以及SQLite常用的语句
在iOS中,根据不同的需求对应的有多种数据存储方式: 1.NSUserdefaults 将数据存储到沙盒中(library),方便易用,但是只能存储系统提供的数据类型(plist),不能存储自定义的 ...
- ios开发之数据存储
iOS应用数据存储的常用方式 XML属性列表(plist)归档 Preference(偏好设置) NSKeyedArchiver归档(NSCoding) SQLite3 Core Data 应用沙盒 ...
- iOS中的数据存储
SQLite3 SQLite3是一款开源的嵌入式关系型数据库,可移植性好,易使用,内存开销小. SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中. SQLite3常用的4种 ...
- Android 学习笔记之数据存储SharePreferenced+File
学习内容: Android的数据存储.... 1.使用SharedPreferences来保存和读取数据... 2.使用File中的I/O来完成对数据的存储和读取... 一个应用程序,经常需要与用 ...
- iOS - OC NSUserDefaults 数据存储
前言 @interface NSUserDefaults : NSObject 用来保存应用程序设置和属性.用户保存的数据.用户再次打开程序或开机后这些数据仍然存在.如果往 userDefaults ...
- iOS - Swift NSUserDefaults 数据存储
前言 public class NSUserDefaults : NSObject 用来保存应用程序设置和属性.用户保存的数据.用户再次打开程序或开机后这些数据仍然存在.如果往 userDefault ...
- MySQL学习笔记之数据存储类型
说明:本文是作者对MySQL数据库数据存储类型的小小总结. Numeric Type (数字类型) 1.TINYINT.SMALLINT.MEDIUMINT.INT.BIGINT主要根据存储字节长度不 ...
- Android开发笔记之: 数据存储方式详解
无论是神马平台,神马开发环境,神马软件程序,数据都是核心.对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用.总体的来讲,数据存储方式有三种:一个是文件,一个是数 ...
随机推荐
- JAVA中的多态概念
多态性是指同一操作作用于某一类对象,可以有不同的解释,产生不同的执行结果. 多态存在的三个必要条件 需要存在继承和实现关系 同样的方法调用而执行不同操作,运行不同代码. 在运行时父类或者接口的引用变量 ...
- SpringBoot JUnit4的断言和注解
Junit4的断言常用方法: assertArrayEquals( new Object[]{ studentService.likeName("小明2").size() > ...
- ubuntu下JDK安装(更新旧版本JAVA)
1.sudo apt-get install openjdk-8-jre openjdk-8-jdk 2.默认会安装在 路径为 /usr/lib/jvm/java-7-openjdk-amd64 下面 ...
- javascript:理解DOM事件
首先,此文不讨论繁琐细节,但是考虑到读者的心灵感受,本着以积极向上的心态,在此还是会列举示例说明. 标题为理解DOM事件,那么在此拿一个简单的点击事件为例,希望大家看到这个例子后能触类旁通. DOM ...
- NYOJ-596-谁是最好的Coder
原题链接 谁是最好的Coder 时间限制:1000 ms | 内存限制:65535 KB 难度:0 描述 计科班有很多Coder,帅帅想知道自己是不是综合实力最强的coder. 帅帅喜欢帅,所以他 ...
- [转载]AngularJS入门教程00:引导程序
我们现在开始准备编写AngularJS应用——phonecat.这一步骤(步骤0),您将会熟悉重要的源代码文件,学习启动包含AngularJS种子项目的开发环境,并在浏览器端运行应用. 进入angul ...
- iptables (2) 基本配置
iptables 基本命令使用举例 一.链的基本操作 1.清除所有的规则.1)清除预设表filter中所有规则链中的规则.# iptables -F -F, --flush [chain] Flush ...
- Virtuabox 虚拟机克隆方法
起初我觉得直接复制一个.vdi 虚拟硬盘再挂上去就可以了,没想到 Virtualbox居然提示UUID重复,看起来就是有点像com生成的那种ID, 查了一下,才知道原来不能这么用 可以通过Vritua ...
- Luogu P1471 方差
题目传送门 开了十倍空间才过是什么鬼?该不会我线段树炸了吧-- 细思极恐 平均数都会求,维护区间和,到时候除一下就好了. 方差的求法如下 (用的Luogu的图片) 因为要维护一个平方,我们可以考虑使用 ...
- 函数定义和调用 -------JavaScript
本文摘要:http://www.liaoxuefeng.com/ 定义函数 在JavaScript中,定义函数的方式如下: function abs(x) { if (x >= 0) { ret ...