iOS - 数据持久化方案

我们在开发过程中,一定会涉及到数据缓存、图片缓存等存储问题。iOS中常用的数据持久化方案有:plist文件、NSUserdefaults、NSKeyedArchiver(归档、解档)、FMDB(sqlite)、CoreData 基本就这几种。

说道数据持久化,首先要问数据储存到哪里?iOS程序默认情况下只能访问程序自己的目录—沙盒。

沙盒有很多目录:

1.Documents:

只有用户生成的文件、应用程序不能重新创建的文件,应该保存在<Application_Home>/Documents 目录下面,并将通过iTunes自动备份。

2.Library:

(1)可以重新下载或重新生成的数据应该保存在<Application_Home>/Library/Caches 目录下面。比如杂志、新闻、地图应用使用的数据库缓存文件和可下载的内容应该保存到这个文件夹。

(2)/Library/Preferences (偏好)保存应用程序的偏好设置文件(使用 NSUserDefaults( 这个就是放这) 类设置时创建,不应该手动创建;连iTunes可备份,在应用程序更新时会自动备份;plist文件就放在此处)

3.tmp:

只是临时使用的数据应该保存到<Application_Home>/tmp 文件夹。尽管iTunes不会备份这些文件,但在应用在使用完这些数据之后要注意随时删除,避免占用用户设备的空间。

//Home 目录
    NSString *homeDirectory = NSHomeDirectory();

    //Documents目录 documents(Documents)
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
    NSString *path = paths.firstObject;

    //Libaray目录
    NSArray * paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *path = paths.firstObject;

    //Caches 目录
    NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *path = paths.firstObject;

那么什么数据该存储到哪个目录里呢,网上有这样一句话根据翻译官方文档总结的:

用户生成的文件放在documents,自己的文件放在library/cache里面———by apple
简单的说明:如果你做个记事本的app,那么用户写了东西,总要把东西存起来。那么这个文件则是用户自行生成的,就放在documents文件夹里面。

如果你有一个app,需要和服务器配合,经常从服务器下载东西,展示给用户看。那么这些下载下来的东西就放在library/cache。

apple对这个很严格,放错了就会被拒。主要原因是ios的icloud的同步问题

说完沙盒目录,我们进入正题,说一下数据持久化的几种方案:

1.plist 文件

plist文件是将某些特定的类,通过xml的方式保存到目录中。可被序列化的类型只有:NSArray、NSMutableArray、 NSDictionary、 NSMutableDictionary 、NSData 、NSMutableData、 NSString 、NSMutableString 、NSNumber、 NSDate

  //1.获取Documents路径
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
   //2.拼接文件路径 
    NSString *fileName = [path stringByAppendingPathComponent:@"fei.plist"];
    //3.存储
    NSArray *array = @[@"one",@"two",@"three",@"four"];
    [array writeToFile:fileName atomically:YES]; 
    //atomically表示是否需要先写入一个辅助文件,再把辅助文件拷贝到目标文件地址。这是更安全的写入文件方法,一般都写YES。

    //4.读取
    NSArray *result  = [NSArray arrayWithContentsOfFile:fileName];
    NSLog(@"%@", result);

2.NSUserDefaults

//1.获得NSUserDefaults单例对象
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向NSUserDefaults中写入内容
    [userDefaults setObject:@"443921990" forKey:@"uid"];
    [userDefaults setBool:YES forKey:@"isNow"];
    [userDefaults setInteger:20 forKey:@"age"];
 //3.立即同步
    [userDefaults synchronize];
 //4.读取文件
    NSString *name = [userDefaults objectForKey:@"uid"];
    BOOL isNow = [userDefaults boolForKey:@"isNow"];
    NSInteger age = [userDefaults integerForKey:@"age"];
    NSLog(@"%@, %d, %ld", name, isNow, age);

一般这里储存应用程序的配置信息的(一般存储的个人信息)。

3.NSKeyedArchiver

归档在iOS中的一种形式的序列化,只要是遵循NSCoding协议的对象都可以通过他实现序列化。由于巨大多数支持存储数据的Foundation和Cocoa Touch类都遵循了NSCoding协议,所以绝大多数的类归档都比较容易实现的。

首先,在需要归档的类中实现NSCoding协议方法。

//实现协议的方法
//解档
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if ([super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];       
    }
    return self;
}

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

然后是使用归档

//获取路径
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"maozhuxi.data"];
    Person *person = [[Person alloc] init];
    person.name = @"李狗嗨";
    person.age = 24;
    //将对象归档是调用NSKeyedArchiver的工厂方法archiveRootObject
    [NSKeyedArchiver archiveRootObject:person toFile:file];

最后是使用解档(在需要的地方)

//需要从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile

    NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"maozhuxi.data"];
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
    if (person) {
        NSLog(@"name == %@", person.name);
        NSLog(@"age == %ld", person.age);
    }

4.FMDB

比较大的数据存储就要用到FMDB,比如聊天信息、界面缓存等等。FMDB是sqlite的基础上进行封装的,pods可以直接下载。

我的项目里面还用到一个LKDBHelper,它用pods也可以下载的,这个第三方是把FMDB也高度封装一下,基本不用sq语句,可以直接把model存进去相当好用,大家可以体验一下,我分享一段我的代码:

.h文件:

#import <Foundation/Foundation.h>
#import <LKDBHelper/LKDBHelper.h>
#import "AddressInfo.h"


#define DB_ADDRESS_PATH [[NSBundle mainBundle] pathForResource:@"Address" ofType:@"db"]

@interface AddressDBManager : NSObject

+ (AddressDBManager *)manager;


//创建表
- (BOOL)loadDatabase;

- (void)insertData;

//获取所有省份数据
- (NSMutableArray *)getProvice;

- (NSMutableArray *)getCityByProvice:(AddressInfo *)model;//通过省份获取直所有的市和县以及单独获取直辖市的区
- 

.m文件:

#import "AddressDBManager.h"

@interface AddressDBManager (){
    LKDBHelper *_dbHelper;
}

@end

@implementation AddressDBManager

+ (AddressDBManager *)manager {
    static dispatch_once_t onceToken;
    static AddressDBManager *shared = nil;
    dispatch_once(&onceToken, ^{ 
       shared = [[AddressDBManager alloc]init];
    });
    return shared;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        NSString * path =  DB_ADDRESS_PATH;
        NSString *documentsDirectory= [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
        NSString *filePath= [documentsDirectory
                             stringByAppendingPathComponent:@"address.db"];
        NSLog(@"++++filePaht%@",filePath);
        [[NSFileManager defaultManager]copyItemAtPath:path toPath:filePath error:nil];
        _dbHelper = [[LKDBHelper alloc]initWithDBPath:filePath];
    }
    return self;
}

- (BOOL)loadDatabase {
    BOOL result = YES;
//    result = [_dbHelper getTableCreatedWithClass:[AddressInfo class]];
    return result;
}

- (void)insertData {
    AddressInfo *model = [[AddressInfo alloc]init];
    model.areaUpperCode = @"123456";
    model.areaCode = @"1234567";
    model.areaName = @"测试";
    BOOL result = [_dbHelper insertToDB:model];
    NSLog(@"%d",result);
}


- (NSMutableArray *)getProvice {
    return  [_dbHelper search:[AddressInfo class] column:nil where:@{@"areaUpperCode":@""} orderBy:nil offset:0 count:40];
}

- (NSMutableArray *)getCityByProvice:(AddressInfo *)model {
    NSMutableArray *array = [NSMutableArray array];
    array = [_dbHelper search:[AddressInfo class] column:nil where:@{@"areaUpperCode":model.areaCode} orderBy:nil offset:0 count:100];
    return array;
}

@end

附加一条删除表的代码:

[dbHelper deleteWithClass:[WDSearchModel class] where:nil];

以上代码敲出来后,有时候我们想通过图形的方式查看,以前在大学学数据库的时候 (那会还是windows),我们用的是MySQL,然后在dos下(终端)能够将表格以图文形式展现出来,在这里我是用DB Browser工具操作的,如下图:

这里写图片描述

(简书上接的图)

5.CoreData




但是给大家推荐一个http://www.jianshu.com/p/aa78b21296ea 这里讲解的很详细。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值