ios 数据持久化

iOS本地数据保存有多种方式,比如NSUserDefaults归档plist文件保存数据库CoreDataKeyChain(钥匙串)等多种方式。其中KeyChain(钥匙串)是保存到沙盒范围以外的地方,也就是与沙盒无关。

沙盒

  • 每个iOS应用程序都有自己的独立目录,这个目录就是应用程序的沙盒。我们可以通过NSHomeDirectory()获取当前应用的家目录,也就是当前应用程序沙盒的根目录。
  • Xcode5以下和Xcode6以上沙盒目录文件夹个数不一样,Xcode6以上有3个文件夹,如下图所示,而Xcode5以下多了一个项目名字.app的文件,比如项目名字为Demo,则沙盒中文件为Demo.app。
沙盒目录结构
  • Xcode5以下和Xcode6以上沙盒的模拟器路径也有变化。如下图为Xcode6沙盒模拟器路径:
沙盒路径
  • 沙盒目录文件分析

    • Documents:保存用户产生的数据,iTunes同步设备的时候会备份该目录。用户产生的数据就是指用户在使用当前app的时候保存的一些数据,比如保存app中的图片、保存下载的文件等。
    • Library:这个目录下有2个文件夹,一个是Caches、一个是Preferences,Caches主要保存缓存数据,比如SDWebImage把缓存的图片就存放到该目录下。当程序退出后,改目录保存的文件一直存在。
      Preferences在Xcode6之前保存的是偏好设置,比如NSUserDefaults保存的文件。但是Xcode6以上就保存到/Users/用户名/Library/ Developer/CoreSimulator/Devices/模拟器UDID/data/Library/Preferences/文件夹下。
    • tmp:保存程序中的临时数据,当程序退出后系统会自动删除tmp中所有的文件。
  • 各个目录的获取方法

Documents:路径获取有3种方法

  1. 利用字符串拼接,在home目录后面拼接字符串Documents。
//获取家目录
NSString *homeDocumentPath = NSHomeDirectory();
//拼接
NSString *documents = [homeDocumentPath stringByAppendingPathComponent:@"Documents"];
  1. NSSearchPathForDirectoriesInDomains方法
// 获取documents目录
//参数1:表示Documents目录。参数2:当前用户目录(user's home directory --- place to install user's personal items)。 参数3:YES 代表展开路径中的波浪字符“~”
NSArray *paths =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// 只有一个documents
NSString *documents = [paths lastObject];

  1. NSFileManager
//获取documents路径
[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]

iOS本地数据保存常用方式

  1. NSUserDefaults
  2. 归档(序列化)
  3. plist文件
  4. 数据库
  5. CoreData
  6. KeyChain

1. NSUserDefaults

  • NSUserDefaults 是一个单例对象,在整个应用程序的生命周期中都只有一个实例。

  • NSUserDefaults保存的数据类型有:NSNumber, 基本数据类型(int,NSInter,float,double,CGFlat......), NSString, NSData, NSArray, NSDictionary, NSURL。

  • NSUserDefaults一般保存配置信息,比如用户名、密码、是否保存用户名和密码、是否离线下载等一些配置条件信息。

  • 基本用法:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//保存值(key值同名的时候会覆盖的)  
[defaults setObject:@"用户名" forKey:kUsernameKey];
//立即保存
[defaults synchronize];
//取值
NSString *username = [defaults objectForKey:kUsernameKey];

  • 同样,保存还有一些方法,比如:
//保存NSInteger
[defaults setInteger:(NSInteger) forKey:(nonnull NSString *)];
//保存BOOL
[defaults setBool:(BOOL) forKey:(nonnull NSString *)];
//保存NSURL
[defaults setURL:(nullable NSURL *) forKey:(nonnull NSString *)];
//保存float
[defaults setFloat:(float) forKey:(nonnull NSString *)];
//保存double
[defaults setDouble:(double) forKey:(nonnull NSString *)];
  • 取值另外方法:
//取值
[defaults integerForKey:(nonnull NSString *)];
[defaults boolForKey:(nonnull NSString *)];
[defaults URLForKey:(nonnull NSString *)];
[defaults floatForKey:(nonnull NSString *)];
[defaults doubleForKey:(nonnull NSString *)];
  • 删除方法:
//删除指定key的数据
[defaults removeObjectForKey:(nonnull NSString *)];
synchronize。立即保存,苹果文档这么说:
Writes any modifications to the persistent domains to disk and updates all unmodified persistent domains to what is on disk.
Return Value YES if the data was saved successfully to disk, otherwise NO.

2. 归档(序列化)

  • 一般保存自定义的对象,但是只有遵守NSCoding的类才能只用归档。

  • 准守NSCoding协议必须要实现两个require方法

    • (void)encodeWithCoder:(NSCoder *)aCoder //归档会触发
    • - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder //解归档会触发
  • Coding类具体实现:

@interface Coding : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;

3. plist文件保存

  • 一般在iOS用plist保存,plist本身就是XML文件,名字后缀为.plist。
  • plist主要保存的数据类型为NSString、NSNumber、NSData、NSArray、NSDictionary。
  • 具体实现:
//把字典写入到plist文件,比如文件path为:~/Documents/data.plist
[dictionary writeToFile:path atomically:YES];
//把数组写入到plist文件中
[array writeToFile:path atomically:YES];
  • 读取数据
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:(nonnull NSString *)]];
NSDictionary *dictionary =  [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:(nullable NSString *) ofType:(nullable NSString *)]];
NSArray *array = [NSArray arrayWithContentsOfURL:[NSURL fileURLWithPath:(nonnull NSString *)]];
NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:(nullable NSString *) ofType:(nullable NSString *)]];

4. 数据库

  • 保存大量数据可以优先考虑用数据库,sql语句对查询操作有优化作用,所以从查询速度或者插入效率都是很高的。
  • sqlite使用步骤:

    • 指定数据库路径。
    • 创建sqlite3对象并且打开数据库。
    • 创建表。
    • 对数据库操作,包括增删改查。
    • 关闭数据库。
  • 具体实现:
    • 数据库路径
 //返回数据库路径,保存到Cache目录下
-(NSString *)databasePath
{
  NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];

  return [path stringByAppendingPathComponent:@"contacts.db"];
}
  • 创建sqlite3对象并且打开数据库,如果数据库打开成功,就创建表。
 //数据库对象
  sqlite3 *contactDB;
 const char *path = [[self databasePath] UTF8String];

 if (sqlite3_open(path, &contactDB) == SQLITE_OK)
 {
      char *errMsg;
      const char *sql_stmt = "CREATE TABLE IF NOT EXISTS CONTACTS(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT,PHONE TEXT)";
     //执行语句
    if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
      {
              //创建表失败
       }
 }
 else 
  {
          //打开数据库失败
  }
  sqlite3_close(contactDB);
  • 代码解释:

    • sqlite3_open:打开指定路径的数据库,如果数据库不存在,就会创建一个新的数据库。
    • SQLITE_OK 是一个常量,表示打开数据库成功。下面是苹果的定义:
    • define SQLITE_OK 0 / Successful result /

    • contactDB 就是数据库对象。
    • sqlite3_exec就是执行sql语句方法。
    • sqlite3_close关闭数据库,一般暂时不用数据库的时候手动关闭,防止资源浪费。
  • 保存数据到数据库

//是一个抽象类型,是一个句柄,在使用过程中一般以它的指针进行操作
sqlite3_stmt *statement;

//数据库路径 
const char *path = [[self databasePath] UTF8String];

//使用的时候打开数据库
if (sqlite3_open(path, &contactDB) == SQLITE_OK)
{
    NSString *insertSQL = [NSString stringWithFormat:@"INSERT INTO CONTACTS (name,address,phone) VALUES(\"%@\",\"%@\",\"%@\")",name.text,address.text,phone.text];

    const char *insert_stmt = [insertSQL UTF8String];
   // 这个函数将sql文本转换成一个准备语句(prepared statement)对象,同时返回这个对象的指针。这个接口需要一个数据库连接指针以及一个要准备的包含SQL语句的文本。它实际上并不执行这个SQL语句,它仅仅为执行准备这个sql语句
    sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
    //执行这个sql
    if (sqlite3_step(statement) == SQLITE_DONE)
    {
        //TODO:已存储到数据库;
    }
    else
    {
        //TODO:保存失败
    }
    //销毁statement对象
    sqlite3_finalize(statement);
    //关闭数据库
    sqlite3_close(contactDB);
}
  • 查询操作
//数据库路径
const char *path = [[self databasePath] UTF8String];
//查询结果集对象句柄
sqlite3_stmt *statement;

//打开数据库
if (sqlite3_open(path, &contactDB) == SQLITE_OK)
{
    //查询的sql语句
    NSString *querySQL = [NSString stringWithFormat:@"SELECT address,phone from contacts where name=\"%@\"",name.text];
    const char *query_stmt = [querySQL UTF8String];

    //执行查询sql语句
    if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) == SQLITE_OK) 
    {
        //遍历每条数据
        if (sqlite3_step(statement) == SQLITE_ROW) 
        {
            //获取每条数据的字段。
            NSString *addressField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
            address.text = addressField;

            NSString *phoneField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 1    )];
            phone.text = phoneField;

            //TODO:已查到结果
        }
        else
        {
            //TODO:未查到结果
        }
        sqlite3_finalize(statement);
    }

    sqlite3_close(contactDB);
}

5. CoreData

CoreData是一门功能强大的数据持久化技术,位于SQLite数据库之上,它避免了SQL的复杂性,能让我们以更自然的方式与数据库进行交互。CoreData提供数据--OC对象映射关系来实现数据与对象管理,这样无需任何SQL语句就能操作他们。
CoreData数据持久化框架是Cocoa API的一部分,⾸次在iOS5 版本的系统中出现,它允许按照实体-属性-值模型组织数据,并以XML、⼆进制文件或者SQLite数据⽂件的格式持久化数据

CoreData与SQLite进行对比

SQLite

1、基于C接口,需要使用SQL语句,代码繁琐
2、在处理大量数据时,表关系更直观
3、在OC中不是可视化,不易理解

CoreData

1、可视化,且具有undo/redo能力
2、可以实现多种文件格式:
    * NSSQLiteStoreType
    * NSBinaryStoreType
    * NSInMemoryStoreType
    * NSXMLStoreTyp
3、苹果官方API支持,与iOS结合更紧密


CoreData核心类与结构

NSManagedObjectContext(数据上下文)

  • 对象管理上下文,负责数据的实际操作(重要)
  • 作用:插入数据,查询数据,删除数据,更新数据

NSPersistentStoreCoordinator(持久化存储助理)

  • 相当于数据库的连接器
  • 作用:设置数据存储的名字,位置,存储方式,和存储时机

NSManagedObjectModel(数据模型)

  • 数据库所有表格或数据结构,包含各实体的定义信息
  • 作用:添加实体的属性,建立属性之间的关系
  • 操作方法:视图编辑器,或代码

NSManagedObject(被管理的数据记录)

  • 数据库中的表格记录

NSEntityDescription(实体结构)

  • 相当于表格结构

NSFetchRequest(数据请求)

  • 相当于查询语句

后缀为.xcdatamodeld的包

  • 里面是.xcdatamodel文件,用数据模型编辑器编辑
  • 编译后为.momd或.mom文件
各类之间关系图
各类之间关系图

6. KeyChain

  • 钥匙串(英文: KeyChain)是苹果公司Mac OS中的密码管理系统。
  • 一个钥匙串可以包含多种类型的数据:密码(包括网站,FTP服务器,SSH帐户,网络共享,无线网络,群组软件,加密磁盘镜像等),私钥,电子证书和加密笔记等。
  • iOS的KeyChain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式。每个iOS程序都有一个独立的KeyChain存储。从iOS 3.0开始,跨程序分享KeyChain变得可行。
  • 当应用程序被删除后,保存到KeyChain里面的数据不会被删除,所以KeyChain是保存到沙盒范围以外的地方。
  • KeyChain的所有数据也都是以key-value的形式存储的,这和NSDictionary的存储方式一样。
  • 相比于NSUserDefaults来说,KeyChain保存更为安全,而且KeyChain里面保存的数据不会因为app删除而丢失。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • Title: iOS数据持久化 ##数据持久化概念 数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型...
    barrylyl阅读 928评论 0 3
  • 1.简介 数据持久存储是一种非易失性存储,在重启动计算机或设备后也不会丢失数据。持久化技术主要用于MVC模型中的m...
    公子无礼阅读 1,660评论 0 4
  • iOS数据持久化方式 文件 归档(NSKeyedArchiver) 属性列表(NSUserDefaults) 数据...
    向阳的向日葵花阅读 884评论 0 12
  • 前言: 在程序开发中,数据层永远是程序的核心结构之一。对这些数据的加工处理是代码中能体现技术水平的一大模块,比如数...
    麦穗0615阅读 1,450评论 3 22
  • IOS数据持久化 数据的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据。在i...
    koula阅读 1,151评论 0 19