iOS本地数据存储

iOS应用数据存储的常用方式

XML属性列表(plist)归档
Preference(偏好设置)
NSKeyedArchiver归档 / NSKeyedUnarchiver解档
SQLite3
FMDB
Core Data

1、沙盒

沙盒也叫沙箱,英文standbox,其原理是通过重定向技术,把程序生成和修改的文件定向到自身文件夹中。在沙盒机制下,每个程序之间的文件夹不能互相访问。iOS系统为了保证系统安全,采用了这种机制

iOS 应用程序在安装时,会创建属于自己的沙盒文件,应用程序不能直接访问其他应用程序的沙盒文件,当应用程序需要向外部请求或接收数据时,都需要经过权限认证,否则,无法获取到数据。

应用程序中所有的非代码文件都保存在沙盒中,比如图片、声音、属性列表,sqlite数据库和文本文件等。


app沙盒目录结构

沙盒的的根目录有三个文件夹,分别是 Documents,Library,tmp


沙盒根目录
  • AppName.app 目录:这是应用程序的程序包目录,包含了所有的资源文件和可执行文件。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动
  • Documents:一般保存应用程序本身产生文件数据,例如游戏进度,绘图软件的绘图等, iTunes备份和恢复的时候,会包括此目录
  • tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
  • Library/Caches: 存放缓存文件,iTunes不会备份,因此文件不会因APP退出而删除(一般使用SDWebImage的缓存资源都是保存到这来)
  • Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
如何获取到对应目录下的路径?
// home
NSString *home = NSHomeDirectory();

// Documents
NSString *docDir1 = [NSString stringWithFormat:@"%@/%@",home,@"Documents"];

NSString *docDir2 = [home stringByAppendingPathComponent:@"Documents"];

NSString *docDir3 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

// Library/Caches
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// Library/Preferences
NSString *preferencesDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"Preferences"];
// tmp
NSString *tempDir = NSTemporaryDirectory();

2、plist

plist是一种明文的轻量级存储方式,这种方式的安全性几乎为0.

  • 特点:只能存储OC常用数据类型(NSString、NSDictionary、NSArray、NSData、NSNumber等类型)而不能直接存储自定义模型对象
    如果想存储自定义模型对象 -> 只能将自定义模型对象转换为字典存储;
/**
 *  Plist文件
 */

- (void)setUpPlist {

    NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [path stringByAppendingPathComponent:@"Person.plist"];
    
    NSDictionary *dict = @{
                           @"name" : @"William",
                           @"age" : @18,
                           @"height" : @1.75f
                           };
    
    // 将数据写入Plist
    [dict writeToFile:filePath atomically:YES];
    NSLog(@"%@", filePath);
    
    // 读取plist中的数据
    NSDictionary *dicts = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"dict = %@",dicts);
    NSString *str = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"str = %@", str);
}
plist日志.png
plist.png

3、Preference(偏好设置)

偏好设置的使用非常方便快捷,我们一般使用它来进行一些设置的记录,比如用户名,开关是否打开等设置。
Preference是通过NSUserDefaults来使用的,是通过键值对的方式记录设置

  • 特点:存储数据不需要关心文件名称,快速存储键值对
重点说明:

(1)偏好设置是专门用来保存应用程序的配置信息的, 一般情况不要在偏好设置中保存其他数据。如果利用系统的偏好设置来存储数据, 默认就是存储在Preferences文件夹下面的,偏好设置会将所有的数据都保存到同一个文件中。
(2)使用偏好设置对数据进行保存之后, 它保存到系统的时间是不确定的,会在将来某一时间点自动将数据保存到Preferences文件夹下面,如果需要即刻将数据存储,可以使用[defaults synchronize];
(3)注意点:所有的信息都写在一个文件中,对比简单的plist可以保存和读取基本的数据类型。
(4)步骤:获取NSuserDefaults,保存(读取)数据
(5)NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。

/**
 *  偏好设置
 */
// 不能保存自定义的对象
- (void)setUpSaveUserDefaults {

    // 获取NSUsersDefault对象(是个单利)
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSLog(@"%@", defaults);
    // 保存数据(注意: 如果设置的数据没有同步, 那么会在将来的某个时刻自动将数据保存到Preference文件夹下面)
    [defaults setObject:@"Mr.William" forKey:@"name"];
    [defaults setInteger:23 forKey:@"age"];
    [defaults setDouble:1.75f forKey:@"height"];
    [defaults setObject:@"man" forKey:@"gender"];
    
    // 强制让数据立刻保存
    [defaults synchronize];
}
Preference存储.png
// 读取数据
- (void)setUpReadUserDefaults {

    // 同样获取NSUserDefault对像
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // 读取数据
    NSString *name = [defaults objectForKey:@"name"];
    NSString *gender = [defaults objectForKey:@"gender"];
    NSInteger age = [defaults integerForKey:@"age"];
    double height = [defaults doubleForKey:@"height"];
    
    NSLog(@"name=%@,gender=%@,age=%ld,height=%.1f",name,gender,age,height);
}
Preference读取.png

4、NSKeyedArchiver归档 / NSKeyedUnarchiver解档

归档和解档会在写入、读出数据之前进行序列化、反序列化,数据的安全性相对高一些。

  • 特点:实现对自定义类的对象进行归档.
序列化与反序列化:

序列化: 将一个OC对象转换成NSData(二进制)的操作就叫做对象的序列化
反序列化: 将本地的二进制数据转为一个OC对象的操作就叫做反序列化

OC对象需要通过遵守NSCoding协议,并且实现协议中的两个方法,才能支持序列化和反序列化操作.

#import <Foundation/Foundation.h>

@class Person;

@interface ArchiverManager : NSObject


+ (instancetype)sharedInstance;

/**
 运用NSKeyedArchiver归档数据
 **/
- (BOOL)writePersonData:(Person *)person;

/**
 使用NSKeyedUnarchiver解档数据
 **/

- (Person *)readPersonData;

/**
 清除数据
 **/

- (BOOL)cleanData;
    
@end

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;

@end
#import "ArchiverManager.h"

@implementation ArchiverManager

+ (instancetype)sharedInstance
{
    static ArchiverManager *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [self new];
    });
    return sharedInstance;
}

/**
 运用NSKeyedArchiver归档数据
 **/
- (BOOL)writePersonData:(Person *)person
{
    NSString *path = [self fullPath];
    NSFileManager *manager = [NSFileManager defaultManager];
    BOOL remove  = [manager removeItemAtPath:path error:nil];
    if (remove)
    {
        NSLog(@"删除成功");
    }
    return [NSKeyedArchiver archiveRootObject:person toFile:path];
}

/**
 使用NSKeyedUnarchiver解档数据
 **/

- (Person *)readPersonData
{
    NSString *path = [self fullPath];
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:path])
    {
        Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        return person;
    }
    return nil;
}

/**
 清除数据
 **/

- (BOOL)cleanData
{
    NSString *path = [self fullPath];
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:path])
    {
        return [fm removeItemAtPath:path error:nil];
    }
    
    return NO;
}

- (NSString *)fullPath
{
    NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
    NSString *path=[docPath stringByAppendingPathComponent:@"Person.data"];
    return path;
}

@end


@implementation Person

//归档
- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeInteger:self.age forKey:@"age"];
}

//解档
-(instancetype)initWithCoder:(NSCoder *)decoder
{
    if (self=[super init]) {
        self.name = [decoder decodeObjectForKey:@"name"];
        self.age = [decoder decodeIntegerForKey:@"age"];
    }
    return self;
}

具体使用

/**
 *  归档
 */

- (void)archiverData
{
    //创建Person对象
    Person *person = [Person new];
    person.name = @"relax";
    person.age = 18;
    
    [[ArchiverManager sharedInstance] writePersonData:person];
    
}

/**
 *  解档
 */

- (void)unarchiverData
{
    Person *person = [[ArchiverManager sharedInstance] readPersonData];
    NSLog(@"name=%@,age=%ld,",person.name,person.age);
}
NSKeyedArchiver.png
image.png

5、SQLite3

SQLite 不区分大小写,但也有需要注意的地方,例如GLOB 和 glob 具有不同作用。

  • 特点:5种基本数据类型 text、integer、float、boolean、blob

SQLite3是无类型的,在创建的时候你可以不声明字段的类型,不过还是建议加上数据类型

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • 移动开发,数据存储是一定而且经常遇到的,存储的数据有大有小,大数据和小数据的存储方式也不一样,存储数据也要考虑性能...
    TigerManBoy阅读 5,192评论 2 5
  • 常见存储方式 Plist 格式文件存储 NSUserDefaults 沙盒存储(个人偏好存储) 文件读写储存 解归...
    季夏_雨阅读 6,755评论 0 14
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 1.NSUserDefaults类 2.Plist文件 3.归档接档 4.数据库 sqlite CoreData ...
    你好8828阅读 559评论 0 0
  • 掰掰手指头,新年就在眼前了.它仿佛已经在向我们欣然招手,可是我却没有一点对于新年的期盼,全然不像小时候那种欢喜...
    花开的声音2616阅读 374评论 0 0