概述

在很多社交App手机在手机没有网络时,重新启动应用,依然能否展示上次访问的数据,提高用户体验,这个就是离线数据存储的运用场景。在iOS开发中常见的离线存储技术有Plist存储、个人偏好存储、解归档、CoreData、SQLite。

Plist存储

Plist存储就是将数据写入一个指定沙盒路径的Plist文件中。如果想要更新已经写入Plist文件中的数据需要全部重新写入,因此不适合大量数据存储。并且Plist存储写入的指定类型中的数据Array、 Dictionary、 String、 Boolean、 Date 、Data 、Number

示例:

- (void)plistCache
{
// Plist存储
// 指定写入Plist文件路径 "/Library/Caches"
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", cachePath); // 字符串写入plist存储
NSString *str = @"123";
[str writeToFile:[cachePath stringByAppendingPathComponent:@"test.plist"] atomically:YES encoding:NSUTF8StringEncoding error:nil]; // 数组写入plist存储
[@[@"jake", @"roes"] writeToFile:[cachePath stringByAppendingPathComponent:@"array.plist"] atomically:YES]; // 字典写入plist存储
NSDictionary *dict = @{@"name":@"jake", @"age":@13, @"height": @1.98};
[dict writeToFile:[cachePath stringByAppendingPathComponent:@"dict.plist"] atomically:YES]; // NSData写入plist存储
NSData *imgData = UIImagePNGRepresentation([UIImage imageNamed:@"timg.jpeg"]);
[imgData writeToFile:[cachePath stringByAppendingPathComponent:@"data.jpeg"] atomically:YES]; }

执行代码,查看沙盒,数据被写入指定的Plist文件中。

偏好设置

偏好设置本质就是Plist存储,系统提供了一个单例NSUserDefaults,每次可以将单个类型value写入沙盒的/Library/Preference目录下的Plist文件中。该Plist命名是应用的Bundle Id。

由于个人偏好设置本质也是Plist存储,因此可以写入数据的基本数据类型只能是Array、 Dictionary、 String、 Boolean、 Date 、Data 、Number

- (void)NSUserDefaultsCache
{
// NSUserDefaults(个人偏好存储)
[[NSUserDefaults standardUserDefaults] setObject:@"jake" forKey:@"name"];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"sex"];
[[NSUserDefaults standardUserDefaults] setDouble:1.78 forKey:@"height"];
// 立即同步
[[NSUserDefaults standardUserDefaults] synchronize]; // 移除个人偏好存储plist中的key-value
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"name"]; // 反归档从沙盒获取数据
[NSKeyedUnarchiver unarchiveObjectWithFile:@"name"];
}

在实际的开发中我们可能存储我们自定对象中的数据,这种需求上面的Plist存储和个人偏好设置存储就不能满足需求了,需要用到下面介绍的解归档存储

解归档

解归档就是将遵守NSCoding对象的数据写入指定沙盒路径的二进制文件。如果利用解归档技术将内存中自定义对象中数据写入沙盒指定文件需要先遵守NSCoding协议。

NSCoding协议

这里我定义Person类,实现NSCoding协议,并将Person实例中的数据通过反归档写入沙盒

/***********************************Person.h*********************************************/
#import <Foundation/Foundation.h> @interface Person : NSObject<NSCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) double height;
@property (nonatomic, assign) BOOL sex;
@end /***********************************Person.m*********************************************/
#import "Person.h" @implementation Person
- (void)encodeWithCoder:(NSCoder *)aCoder
{
// 告诉系统哪些属性需要归档
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeDouble:self.height forKey:@"height"];
[aCoder encodeInt:self.age forKey:@"age"];
[aCoder encodeBool:self.sex forKey:@"sex"];
} - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.height = [aDecoder decodeDoubleForKey:@"height"];
self.age = [aDecoder decodeIntForKey:@"age"];
self.sex = [aDecoder decodeBoolForKey:@"sex"];
}
return self;
} - (NSString *)description
{
NSString *string = [NSString stringWithFormat: @"name=%@, height=%f, age=%d, sex=%d", self.name, self.height, self.age, self.sex];
return string;
} 解归档Person示例
- (void)archiverCache
{
// 获取路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; // 归档
// 对于开发中自定义的数据模型的储存,我们可以考虑使用归档储存方案。
Person *p = [[Person alloc] init];
p.name = @"jake";
p.height = 1.78;
p.age = 18;
p.sex = YES;
[NSKeyedArchiver archiveRootObject:p toFile:[cachePath stringByAppendingPathComponent:@"pData"]]; // 返归档从沙盒中取出Person示例对象
id person = [NSKeyedUnarchiver unarchiveObjectWithFile:[cachePath stringByAppendingPathComponent:@"pData"]];
NSLog(@"%@", person);
}

CoreData

CoreData 是一个纯粹面向对象的框架,可以管理实体以及实体之间的关联关系的持久化,也就是我们常说的数据持久化。

但是由于它是一个重量级的数据库管理,产生很多代码量。对于复杂的联合表查询不适用 并且出错不容易解决或找到问题,需要有很深的开发功底。

目前开发一般使用嵌入式数据库SQLite替代。这里就不详细介绍了。

SQLite

SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。

SQLite 是非常小的,是轻量级的,完全配置时小于 400KiB,省略可选功能配置时小于250KiB。

SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运

SQLite数据类型

SQLite数据类型 对应OC类型
INTEGER 整型
TEXT 文本
REAL 浮点型
BLOB 二进制数据

注意:SQLite这里没有对应OC中的BOOL类型。

SQLite语句

对于SQLite的语句已基本与MySQLite一直,可以参考我的博客MySQL

这里有两点需要注意下,设置主键自动增长使用AUTOINCREMENT,不要使用MySQL的auto_increment带下划线的样式。

SQLite在应用

对于iOS程序使用SQLite苹果提供了静态库

sqlite3提供的接口纯C语言,开发起来比较费劲,一般我们使用GitHub的对其封装的第三方库FMDB

对于FMDB的使用可以参考我简书上的博客FMDB使用

iOS开发系列-常见离线存储方式的更多相关文章

  1. 怎样实现IOS开发中的数据存储方式

    iOS 开发中,一般有如下几种数据存储方式.需要根据具体的业务场景,选择 合适的数据存储方式. (1)  用户默认设置 – 这种情况通常不需要用户干预,如游戏通关信息,Video 播放记录,或者 Ap ...

  2. 【Xamarin 挖墙脚系列:IOS 开发界面的3种方式】

    原文:[Xamarin 挖墙脚系列:IOS 开发界面的3种方式] xcode6进行三种基本的界面布局的方法,分别是手写UI,xib和storyboard.手写UI是最早进行UI界面布局的方法,优点是灵 ...

  3. iOS开发系列--App扩展开发

    概述 从iOS 8 开始Apple引入了扩展(Extension)用于增强系统应用服务和应用之间的交互.它的出现让自定义键盘.系统分享集成等这些依靠系统服务的开发变成了可能.WWDC 2016上众多更 ...

  4. iOS开发系列--Swift进阶

    概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...

  5. iOS开发系列--让你的应用“动”起来

    --iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...

  6. iOS开发系列--让你的应用“动”起来

    --iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...

  7. IOS开发系列 --- 核心动画

    原始地址:http://www.cnblogs.com/kenshincui/p/3972100.html 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥i ...

  8. iOS开发系列--让你的应用“动”起来【转载】

    概览 原文链接:http://www.cnblogs.com/kenshincui/p/3972100.html 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥i ...

  9. iOS开发系列之app的一天

    本文主要讲述我对 iOS 开发的一些理解,希望能通过 app 从启动到退出,将一些的知识整合起来,形成一条知识链,目前涉及到的知识点有 runloop.runtime.文件存储.界面布局.离线推送.内 ...

随机推荐

  1. \t \r \n转义字符

    t \r \n都是转义字符,空格就是单纯的空格,输入时可以输入空格 \t 的意思是 横向跳到下一制表符位置 \r 的意思是 回车 \n 的意思是回车换行 所有的转义字符和所对应的意义: 转义字符 意义 ...

  2. 常用内置模块(四)——subprocess、re

    常用模块(四) 一.subprocess模块 1.subprocess为子流程模块,用于执行系统命令,该模块在Python全栈开发中不常用 2.常用方法 run 返回一个表示执行结果的对象 call ...

  3. java 生成随机数字+字母组合 和字母组合

    生成随机数包含数字,字母 /** * 生成随机数当作getItemID * n : 需要的长度 * @return */ private static String getItemID( int n ...

  4. 关于VS的第一次使用

    参考链接:https://blog.csdn.net/qq_36556893/article/details/88605617

  5. Reqests----Get请求之参数化

    一.环境安装 >>pip install requests 注意:pip很容易就会版本升级,如果用python3的,请使用pip3 install requests 1.初始化版本 2.把 ...

  6. elasticsearch 父子文档(十一)

    说明 需求 一个产品多个区域销售 每个区域有自己的价格, 方式1冗余行,a 产品分别在  area1 area2 area3区域销售 a产品就会生成3条产品数据 搜索id去重就行了,但是问题就是 聚合 ...

  7. Comparable和Comparator接口是干什么的?列出它们的区别

    Java提供了只包含一个compareTo()方法的Comparable接口.这个方法可以个给两个对象排序.具体来说,它返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象. Java提供了 ...

  8. ES6面试 知识点汇总(全)

    近期在复习ES6,针对ES6新的知识点,以问答形式整理一个全面知识和问题汇总.(全干货,适合对ES6有一定理解的同学复习,以及ES6面试.) 一.问:ES6是什么? 答: ES6是新一代的JS语言标准 ...

  9. leetcode-399-除法求值

    方法一:dfs+图 class Solution: def calcEquation(self, equations: List[List[str]], values: List[float], qu ...

  10. 通过网络socket获取对方 ip 和port

    int getpeername(int s, struct sockaddr *name, socklen_t *namelen);描述获取socket的对方地址struct sockaddr_in ...