前面已经讲解了SQLite,FMDB以及CoreData的基本操作和代码讲解(CoreData也在不断学习中,上篇博客也会不断更新中)。本篇我们将讲述在实际开发中,所使用的iOS数据持久化的方式以及怎么会使用到这些方式,都会以本人实际开发的场景为例,大约需要花10-15分钟,欢迎大家指正。

一、前言

和大家说一个真实故事,前年我去美图面试(当时的技术仅仅是UI和接口的实现,并不注重很多底层实现和很多概念的原理,换句话说,就是真正的码农),过了技术第一轮和第二轮(前两年的也就是问问技术点的实现),到了第三轮的时候,应该是项目经理面试我,其中一个题目问住了我,因为iOS我是自学的,也算是不断摸索的。

“请你说一下iOS 一般会默认自己程序的目录,请说一下这个目录机构,以及组成部分,里面包含什么?”

当时的情景就是,我是谁,我在哪,大家也可以想一下!!!

其实那个项目经理问的就是我们经常听到的沙盒文件,其中iOS在程序默认下只会访问自己的程序目录-也就是沙盒文件。

1. 寻找沙盒文件位置

大家可能不知道怎么查看正在真机(或者模拟器)运行下的沙盒文件,可以按照下面的步骤查看

1.1 第一步,打开项目,选择windows(我是以真机为例,模拟器亦是)

1.2 第二步,进入界面,选择自己的app,点击绿色按钮,

1.3 第三步,选择第二个Download Container,导出到指定的文件夹(我是导出到桌面)

1.4 最后,我们发现桌面有个后缀名为.xcappdata的文件夹,我是导入到桌面。

2.沙盒文件目录结构

2.1  在1.4中后缀.xcappdata,右击选择->显示包内容,打开看到目录如下图,也可以继续点击查看更详细内容。

2.2目录讲解

:->AppData:也就是应用程序包,存的是程序的源文件,其中里面有可执行的文件以及资源文件。通过以下可以获得路径

 NSString *path = [[NSBundle mainBundle] bundlePath];
NSLog(@"%@", path);

AppData里面包括了以下内容:

(1)Documents

也是我们经常使用到的目录,我们经常看到iTunes同步,同步的就是此文件中的内容,Documents适合存比较重要的数据。我们可以通过以下代码拿到Documents

NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", path);

(2)Library

Library比较适合存储比较大的数据,并且iTunes不会同步此文件,也不会备份。可以通过以下拿到路径

NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", path);

(2.1)获取Caches目录路径

 NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"Caches目录路径是%@",docDir);

(2.2)Preferences

主要包括了程序中的偏好设置文件,下面会讲述这个Preferences

(3)SystemData

目前暂不讲解这个目录(里面目录为空)

(4)tmp

用于存储临时文件,主要保存程序再次启动中不需要的信息数据,并且该路径中的文件并不会被itunes同步和备份。通过以下获得

NSString *tmpDir =  NSTemporaryDirectory();

上面就是前言部分,大家这篇博客,我们主要讲述iOS数据持久化操作,好,我们正式以项目的形式讲述iOS的数据持久化操作。

二、iOS数据持久化操作

对于iOS的数据持久化操作,在网上也是有很多讲解,本篇主要讲述本人项目中使用到的方式进行讲解。iOS持久化操作方式主要有以下五种方式:

1. plist文件方式,也就是属性列表

2. preference 也就是偏好设置

3. NSKeyedArchiver 也就是归档

4. SQLite

5. CoreData

下面我们就一一讲解五种方式,以项目为例。

2.1 plist (属性列表)

plist是将比较特定的类(不经常改变的类),通过XML的方式存储在目录中。

自己项目有个分享的功能,因为分享渠道是固定的以及界面内容不会改变,所以自己当初采取plist文件的方式进行存储。效果如下:

具体分享平台自己使用plist文件进行存储,下面是自己plist文件

点开plist文件,如下图

右击该plist文件->选择Open As ->选择Source Code,如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>data</key>
<array>
<dict>
<key>titleLabel</key>
<string>微信好友</string>
<key>imageView</key>
<string>cart_wx</string>
</dict>
<dict>
<key>titleLabel</key>
<string>朋友圈</string>
<key>imageView</key>
<string>cart_friend</string>
</dict>
<dict>
<key>titleLabel</key>
<string>QQ好友</string>
<key>imageView</key>
<string>cart_qq</string>
</dict>
<dict>
<key>titleLabel</key>
<string>QQ空间</string>
<key>imageView</key>
<string>cart_que</string>
</dict>
</array>
</dict>
</plist>

下面讲述怎么使用分享plist文件。

通过上图和XML文件可以看出最外面是字典,我在项目是使用懒加载方式加载这个字典

代码如下:

- (NSDictionary *)configDatas{
if (!_configDatas) {
NSString *path = [[NSBundle mainBundle]pathForResource:@"IOACartShareDatas" ofType:@".plist"];
NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
_configDatas = dic;
}
return _configDatas;
}

在分享的view内进行传值

然后进入shareView中查看具体赋值,布局采用了UICollectionView布局

补充一下:

自己上面是一个一个在plist里面创建的元素,也可以通过writeToFile存储以及arrayWithContentsOfFile取文件。

(1)writeToFile存储方式

NSArray *array = @[@"2", @"1", @"3"];
[array writeToFile:fileName atomically:YES];

(2)arrayWithContentsOfFile读取方式

NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"%@", result);

2.2 Preference偏好设置

Preference偏好设置一般用存储应用程序的配置信息文件,最好不要在Preference中存储其他数据,Preference通过操作NSUserDefaults完成操作。

2.2.1 获得NSUserDefaults文件

//获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

2.2.2 开始向文件中写入内容

[userDefaults setObject:@"哈哈哈" forKey:@"a"];
[userDefaults setBool:YES forKey:@"success"];
[userDefaults setInteger: forKey:@"age"];

2.2.3 确定是否同步。确定是否调用synchronize方法,想要写入文件时,就应该调用[userDefaults synchronize]方法

如果同步

[userDefaults synchronize];

反之,不写。

2.2.4 在合适的地方调取文件

NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"success"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);

Preference会把所有的数据存储到一个文件中,也就是在上面preference文件下的plist文件。

2.3 NSKeyedArchiver 归档

在使用归档NSKeyedArchiver一定要遵守NSCoding协议,也就是遵守了NSCoding协议的对象,我们都可以通过归档NSKeyedArchiver进行序列化。

通过查看NSCoding协议文件,发现如下

NSCoding协议文件声明了两个文件,上述图中,也是必须要实现的。encodeWithCoder用于将对象编码到归档中,而initWithCoder用于通过解档来获取一个新对象。

需要注意的是:

假如要归档的类恰好是一个自定义类的子类时候,就应该要在归档和解档之前要首先实现父类的方法,也就是必须要实现以下两个方法:[super encodeWithCoder:aCoder]和[super initWithCoder:aDecoder]

拓展->

NSCopying协议文件如下(有一次面试官问我,NSCopying与NSMutableCopying),大家当增长一个知识点吧!

下面以自己以前的项目为准,讲述归档的使用(因为以前项目较小,又是独立开发,采用NSKeyedArchiver存储信息)。

2.3.1 使用NSKeyedArchiver归档存储用户登录部分信息,注销登录清除。定义了一个类AppUserDefaults

点开AppUserDefaults.h文件定义登录获取的属性(仅仅展示部分属性,实现都一样)

通过以下方法对登录信息的赋值

我们看一下归档和解档,以及上面方法的实现(注解上面type属性是代表是不同短登录:例如医生端和患者端)

2.3.2 encodeWithCoder归档(显示部分属性,否则界面太大)

2.3.2 initWithCoder解档

2.3.2 登录通过setSessionWithLoginName设置属性

+ (void)setSessionWithLoginName:(NSString *)loginName
version:(NSString *)version
loginTime:(long long)loginTime
id_:(long)id_
userType:(int)userType
name:(NSString *)name
phone:(NSString *)phone
pic:(NSString *)pic
companyName:(NSString *)companyName
address:(NSString *)address
type:(NSInteger)type
cityName:(NSString *)cityName
cityId:(long)cityId
latitude:(NSString *)latitude
longitude:(NSString *)longitude {
//判断版本号,通过session
AppUserDefaults *session = [AppUserDefaults getSession];
if (session && ![session.version isEqualToString:@""]) {
if (type != -)
session.type = type;
if (loginTime != -)
session.loginTime = loginTime;
if ([loginName isNotBlank])
session.loginName = loginName;
if ([version isNotBlank])
session.version = version;
if (id_ != -)
session.id_ = id_;
}
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:session];
if (data) {
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"session"];
[user synchronize];
}
} + (AppUserDefaults *)getSession {
AppUserDefaults *session = nil;
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSData *data = [user objectForKey:@"session"];
if (data) {
session = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if (session && [session.version isEqualToString:@""]) {
session = nil;
}
}
return session;
}

2.3.4 上面就是AppUserDefaults文件内容,下面讲述在登录时候进行赋值。

首先要懒加载AppUserDefaults

- (AppUserDefaults *)userDefaults{
if (_userDefaults == nil) {
_userDefaults = [AppUserDefaults getSession];
}
return _userDefaults;
}

登录成功时赋值

2.3.5 如果用户注销之后或者退出应用应该给重新清空,如下:

总结:

使用NSKeyedArchiver的工厂方法[NSKeyedArchiver archiveRootObject:obj toFile:path];方法。demo如下:

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"student.data"];
Person *person = [[Person alloc] init];
person.avatar = self.avatarView.image;
person.name = self.nameField.text;
person.age = [self.ageField.text integerValue];
[NSKeyedArchiver archiveRootObject:person toFile:file];

如果想解档需要调用[NSKeyedUnarchiver unarchiveObjectWithFile:path];方法如下

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"student.data"];
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
if (person) {
self.avatarView.image = person.avatar;
self.nameField.text = person.name;
self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
}

在这之前还是要定义属性和实现协议方法

//1.遵循NSCoding协议
@interface student : NSObject //2.设置属性
@property (strong, nonatomic) UIImage *avatar;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
@end
 //解档
- (id)initWithCoder:(NSCoder *)aDecoder {
if ([super init]) {
self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.avatar forKey:@"avatar"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}

2.4 SQLite

以下并不是推广博客,主要是很多内容,没有必要写第二遍,即使写,也没用专门一篇详细。

关于SQLite讲解,请查看以前博客https://www.cnblogs.com/guohai-stronger/p/9218175.html

SQLite的使用还是很麻烦的,在一般的项目开发中,会使用FMDB操作,这个也有讲解,https://www.cnblogs.com/guohai-stronger/p/9246653.html

对于SQLite和FMDB的使用区别,看这篇博客希望对大家有所帮助 https://www.cnblogs.com/guohai-stronger/p/9251131.html

2.5 CoreData

CoreData目前自己所从事的工作还没有使用过CoreData,但自己通过尝试demo,还是有所感悟,关于CoreData的理解,自己也写了一个博客,https://www.cnblogs.com/guohai-stronger/p/9254293.html

以上就是iOS数据存储的5中方式,都是自己真实项目所使用的,希望对大家有所帮助 !!!如有错误的地方请告诉我,大家共同进步。

iOS -数据持久化方式-以真实项目讲解的更多相关文章

  1. iOS数据持久化方式及class_copyIvarList与class_copyPropertyList的区别

    iOS数据持久化方式:plist文件(属性列表)preference(偏好设置)NSKeyedArchiver(归档)SQLite3CoreData沙盒:iOS程序默认情况下只能访问自己的程序目录,这 ...

  2. iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】

                   在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运 ...

  3. iOS中的数据持久化方式

    iOS中的数据持久化方式,基本上有以下四种:属性列表.对象归档.SQLite3和Core Data. 1.属性列表 涉及到的主要类:NSUserDefaults,一般 [NSUserDefaults ...

  4. iOS 数据持久化(扩展知识:模糊背景效果和密码保护功能)

    本篇随笔除了介绍 iOS 数据持久化知识之外,还贯穿了以下内容: (1)自定义 TableView,结合 block 从 ViewController 中分离出 View,轻 ViewControll ...

  5. 四种数据持久化方式(下) :SQLite3 和 Core Data

    在上文,我们介绍了iOS开发中的其中2种数据持久化方式:属性列表.归档解档. 本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运用: 在本节,将通过对4个文 ...

  6. iOS开发笔记-swift实现iOS数据持久化之归档NSKeyedArchiver

    IOS数据持久化的方式分为三种: 属性列表 (plist.NSUserDefaults) 归档 (NSKeyedArchiver) 数据库 (SQLite.Core Data.第三方类库等 归档(又名 ...

  7. IOS数据持久化之归档NSKeyedArchiver

    IOS数据持久化的方式分为三种: 属性列表 (自定义的Property List .NSUserDefaults) 归档 (NSKeyedArchiver) 数据库 (SQLite.Core Data ...

  8. iOS开发中的4种数据持久化方式【一、属性列表与归档解档】

    iOS中的永久存储,也就是在关机重新启动设备,或者关闭应用时,不会丢失数据.在实际开发应用时,往往需要持久存储数据的,这样用户才能在对应用进行操作后,再次启动能看到自己更改的结果与痕迹.ios开发中, ...

  9. iOS数据持久化-OC

    沙盒详解 1.IOS沙盒机制 IOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文 ...

随机推荐

  1. Yaf 完全精通

    bugs 这样 _Bootstrap 的话,会导致严重的后果,cpu 100%

  2. How to setup Visual Studio without pain

    Visual Studio (VS) can be very hard to install. If you are lucky, one whole day may be enough to ins ...

  3. php Glob() 使用 查找文件:

    1. 取得所有的后缀为PHP的文件(加上路径)$file=glob('D:/phpStudy/WWW/prictue/*.php');print_r($file);//如果没有指定文件夹的话就是显示出 ...

  4. Windows 10 IoT Serials 10 – 如何使用OCR引擎进行文字识别

    1. 引言 OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别方 ...

  5. Hadoop Partition函数应用(归档)

    一.实例描述 在这个实例里我们使用简单的数据集,里面包含多条数据,每条数据由姓名.年龄.性别和成绩组成.实例要求是按照如下规则归档用户. 1.找出年龄小于20岁中男生和女生的最大分数 2.找出20岁到 ...

  6. redis入门知识汇总

    1.什么是redis? Redis 是一个基于内存的高性能key-value数据库. 2.Reids的特点 Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库 ...

  7. springboot2.0jar包启动异常

    今天碰到一个异常: 08:44:07.214 [main] ERROR org.springframework.boot.SpringApplication - Application run fai ...

  8. gdb remote 使用

    //设置halt (gdb) set {int}0x400b0000 = 0x1(gdb) load //设置下一个pc指针的值(gdb) set {int}0x400b2000 = 0x80(gdb ...

  9. Python - IPython

    1- IPython简介 HomePage:http://ipython.org/ IPython(interactive Python) provides a rich architecture f ...

  10. 如何写一个适配iPhoneX的底部导航

    引言 iPhoneX发布至今已经有将近一年的时间了,各类app都多多少少做了对iPhoneX的适配,那对于我们H5页面该做哪方面的适配呢? 首先了解安全区域(safe area)的概念,它保证了内容在 ...