ios本地存储的五种方式

作者: 涣然 | 来源:发表于2018-08-10 19:22 被阅读1132次
  1. 本文参考自:iOS 本地持久化存储
    作者:哆啦_
  2. 本文参考自:iOS CoreData数据库之创建详解
    作者:tanyufeng

ios数据存储的5种方式

  1. NSUserDefaults(Preference偏好设置)
  2. plist存储
  3. 归档
  4. SQLite3
  5. CoreData

应用沙盒

Document:适合存储重要的数据, iTunes同步应用时会同步该文件下的内容,(比如游戏中的存档)
Library/Caches:适合存储体积大,不需要备份的非重要数据,iTunes不会同步该文件
Library/Preferences:通常保存应用的设置信息, iTunes会同步
tmp:保存应用的临时文件,用完就删除,系统可能在应用没在运行时删除该目录下的文件,iTunes不会同步

获取沙盒路径

Document:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFilePath = paths.firstObject;

NSuserDefault

NSuserDefault适合存储轻量级的本地数据,支持的数据类型有:NSNumber,NSString,NSDate,NSArray,NSDictionary,BOOL,NSData

沙盒路径为 Library/Preferences
文件格式为 .plist

优点:

  1. 不需要关心文件名
  2. 快速进行键值对存储
  3. 直接存储基本数据类型

缺点:

  1. 不能存储自定义数据
  2. 取出的数据都是不可变的
- (IBAction)userDefaultSave:(id)sender {
    NSArray *testArray = @[@"test1", @"test2", @"test3"];
    [[NSUserDefaults standardUserDefaults] setObject:testArray forKey:@"arrayKey"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
- (IBAction)userDefaultLoad:(id)sender {
    NSArray *testArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"arrayKey"];
    NSLog(@"%@", testArray);
}

plist存储

plist支持的数据类型:

NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;
不支持BOOL
而且最外层好像要用`NSArray 或 NSDictionary,偷个懒还没验证
- (IBAction)plistSave:(id)sender {
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:@"testPlist.plist"];
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:@"ran" forKey:@"name"];
    [dict setObject:@"18" forKey:@"age"];
    [dict writeToFile:filePath atomically:YES];
}

- (IBAction)plistLoad:(id)sender {
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:@"testPlist.plist"];
    
    NSDictionary *t = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"%@",t);
}

归档

存储自定义对象

  1. 首先新建Person类,并遵守NSCoding协议
@interface Person : NSObject<NSCoding>

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

@end
  1. 实现协议方法
@implementation Person

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        _name = [coder decodeObjectForKey:@"name"];
        _age = [coder decodeObjectForKey:@"age"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{

    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeObject:self.age forKey:@"age"];

}
@end
  1. 归档解档
- (IBAction)archive:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    Person *p1 = [[Person alloc] init];
    p1.name = @"ran";
    p1.age = @"18";
    
    [NSKeyedArchiver archiveRootObject:p1 toFile:filePath];
}

- (IBAction)unarchive:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    Person *p1 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath] ;
    
    NSLog(@"%@", p1.name);
    NSLog(@"%@", p1.age);
}

但是这种方法只能存储一个对象,存储多个对象要采用如下的方法:

- (IBAction)archiveManyObject:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    NSMutableData *data = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver =  [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //将数据区连接到NSKeyedArchiver对象
    
    Person *p1 = [[Person alloc] init];
    p1.name = @"ran1";
    p1.age = @"18";
    [archiver encodeObject:p1 forKey:@"person1"];
    
    Person *p2 = [[Person alloc] init];
    p2.name = @"ran2";
    p2.age = @"19";
    [archiver encodeObject:p2 forKey:@"person2"];

    [archiver finishEncoding];
    
    [data writeToFile:filePath atomically:YES];
}

- (IBAction)unarchiveManyObject:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    Person *p1 =  [unarchiver decodeObjectForKey:@"person1"];
    Person *p2 =  [unarchiver decodeObjectForKey:@"person2"];
    [unarchiver finishDecoding];
    
    NSLog(@"%@", p1.name);
    NSLog(@"%@", p2.name);
}

SQLite3

数据库(splite):
splite是一个轻量级,跨平台的小型数据库,可移植性比较高,有着和MySpl几乎相同的数据库语句,以及无需服务器即可使用的优点:

数据库的优点:

  1. 该方案可以存储大量的数据,存储和检索的速度非常快.
  2. 能对数据进行大量的聚合,这样比起使用对象来讲操作要快.

数据库的缺点:

  1. 它没有提供数据库的创建方式
  2. 它的底层是基于C语言框架设计的, 没有面向对象的API, 用起来非常麻烦
  3. 发杂的数据模型的数据建表,非常麻烦
    在实际开发中我们都是使用的是FMDB第三方开源的数据库,该数据库是基于splite封装的面向对象的框架.
#import "SqliteVC.h"
#import "Person.h"
@interface SqliteVC() {
    
    sqlite3 *_db;

}
@end

@implementation SqliteVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"];
    NSLog(@"fileName = %@",fileName);
    
    int result = sqlite3_open(fileName.UTF8String, &_db); //创建(打开)数据库,如果数据库不存在,会自动创建  数据库文件的路径必须以C字符串(而非NSString)传入
    
    if (result == SQLITE_OK) {
        NSLog(@"成功打开数据库");
        
        char *errorMesg = NULL;
        const char *sql = "create table if not exists t_person (id integer primary key autoincrement, name text, age integer);";
        int result = sqlite3_exec(_db, sql, NULL, NULL, &errorMesg); //sqlite3_exec()可以执行任何SQL语句,比如创表、更新、插入和删除操作。但是一般不用它执行查询语句,因为它不会返回查询到的数据
        
        if (result == SQLITE_OK) {
            NSLog(@"成功创建t_person表");
        } else {
            NSLog(@"创建t_person表失败:%s",errorMesg);
        }
        
    } else {
        NSLog(@"打开数据库失败");
    }
}
- (IBAction)insert:(id)sender {
    for (int i = 0; i < 30; i++) {
        
        NSString *name = [NSString stringWithFormat:@"person-%d",arc4random()%100];
        int age = arc4random() % 100;
        
        char *errorMesg = NULL;
        NSString *sql = [NSString stringWithFormat:@"insert into t_person (name,age) values ('%@',%d);",name, age];
        int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
        
        if (result == SQLITE_OK) {
            NSLog(@"添加数据成功");
        } else {
            NSLog(@"添加数据失败");
        }
    }
}

- (IBAction)delete:(id)sender {
    char *errorMesg = NULL;
    NSString *sql = @"delete from t_person where age >= 0";
    int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
    
    if (result == SQLITE_OK) {
        NSLog(@"删除成功");
    }else {
        NSLog(@"删除失败");
    }
}

- (IBAction)query:(id)sender {
    const char *sql = "select id, name, age from t_person;";  //"select id, name, age from t_person where age >= 50;"
    sqlite3_stmt *stmt = NULL;  //定义一个stmt存放结果集
    int result = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL); //检测SQL语句的合法性
    
    if (result == SQLITE_OK) {
        NSLog(@"查询语句合法");
        
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            
            int ID = sqlite3_column_int(stmt, 0);
            const unsigned char *sname = sqlite3_column_text(stmt, 1);
            NSString *name = [NSString stringWithUTF8String:(const char *)sname];
            int age = sqlite3_column_int(stmt, 2);
            
            NSLog(@"%d %@ %d",ID, name, age);
        }
    } else {
        NSLog(@"查询语句非法");
    }
}

- (IBAction)update:(id)sender {
    NSString *sql = @"update t_person set name = '哈哈' where age > 60";
    char *errorMesg = NULL;
    int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
    
    if (result == SQLITE_OK) {
        NSLog(@"更改成功");
    }else {
        
        NSLog(@"更改失败");
    }
}


coreData

coreData是苹果官方在iOS5之后推出的综合性数据库,其使用了对象关系映射技术,将对象转换成数据,将数据存储在本地的数据库中
coreData为了提高效率,需要将数据存储在不同的数据库中,比如:在使用的时候,最好是将本地的数据保存到内存中,这样的目的是访问速度比较快.

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文件
类关系图
开始创建coredata
步骤:
1.创建模型文件 [相当于一个数据库]
2.添加实体 [一张表]
3.创建实体类 [相当模型--表结构]
4.生成上下文 关联模型文件生成数据库
  1. 创建模型文件
    New File -> iOS -> Core Data ->Data Model
  1. 创建实体
创建实体
Codegen
  1. 创建实体类
创建实体类

创建结果如图所示:


创建结果
  1. 生成上下文 关联模型文件生成数据库,进行增删查改操作
#import "coredataVC.h"
#import <CoreData/CoreData.h>
#import "Student+CoreDataProperties.h"

@interface coredataVC ()

@property(nonatomic, strong)NSManagedObjectContext *context;

@end

@implementation coredataVC

- (void)viewDidLoad {
    [super viewDidLoad];

    //entity 记得勾选 language:objective-c 和 codegen:manual/none
    [self createSql];
}

- (void)createSql {
    //获取模型路径
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Person" withExtension:@"momd"];
    //根据模型文件创建模型对象
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    
    //利用模型对象创建持久化存储助理
    NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    
    //数据库的名称和路径
    NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *sqlPath = [docStr stringByAppendingPathComponent:@"coreData.sqlite"];
    NSURL *sqlUrl = [NSURL fileURLWithPath:sqlPath];
    NSLog(@"数据库 path = %@", sqlPath);
    
    NSError *error = nil; //设置数据库相关信息 添加一个持久化存储库并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库
    [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:nil error:&error];
    
    if (error) {
        NSLog(@"添加数据库失败:%@",error);
    } else {
        NSLog(@"添加数据库成功");
    }
    
    //3、创建上下文 保存信息 对数据库进行操作 关联持久化助理
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    context.persistentStoreCoordinator = store;
    _context = context;
}

- (IBAction)insertClick:(id)sender {
    Student * student = [NSEntityDescription  insertNewObjectForEntityForName:@"Student"  inManagedObjectContext:_context];
    student.name = [NSString stringWithFormat:@"stu-%d",arc4random()%100];
    student.age = arc4random()%30;
    
    NSError *error = nil;
    if ([_context save:&error]) {
        NSLog(@"数据插入到数据库成功");
    }else{
        NSLog(@"数据插入到数据库失败");
    }
}

- (IBAction)deleteClick:(id)sender {
    //创建删除请求
    NSFetchRequest *deleRequest = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    
    //删除条件 没有任何条件就是读取所有的数据
    //NSPredicate *pre = [NSPredicate predicateWithFormat:@"age < %d", 10];
    //deleRequest.predicate = pre;
    
    //返回需要删除的对象数组
    NSArray *deleArray = [_context executeFetchRequest:deleRequest error:nil];
    
    //从数据库中删除
    for (Student *stu in deleArray) {
        [_context deleteObject:stu];
    }
    
    NSError *error = nil;
    if ([_context save:&error]) {
        NSLog(@"删除数据成功");
    }else{
        NSLog(@"删除数据失败, %@", error);
    }
}

- (IBAction)queryClick:(id)sender {
    //创建查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    
    //查询条件 没有任何条件就是读取所有的数据
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"age >= 0"];
    request.predicate = pre;
    
    // 从第几页开始显示 通过这个属性实现分页
    //request.fetchOffset = 0;
    // 每页显示多少条数据
    //request.fetchLimit = 6;
    
    //发送查询请求
    NSArray *resArray = [_context executeFetchRequest:request error:nil];
    
    //打印查询结果
    for (Student *stu in resArray) {
        NSLog(@"name=%@, age=%d",stu.name, stu.age);
    }
}

- (IBAction)updateClick:(id)sender {
    //创建查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"age >= 0"];
    request.predicate = pre;
    
    //发送请求
    NSArray *resArray = [_context executeFetchRequest:request error:nil];
    
    //修改
    for (Student *stu in resArray) {
        stu.name = @"ran";
    }
    
    NSError *error = nil;
    if ([_context save:&error]) {
        NSLog(@"更新数据成功");
    }else{
        NSLog(@"更新数据失败, %@", error);
    }
}

@end

相关文章

  • iOS 本地存储, 无需再写SQL语句 <封装 FMDB&

    iOS,本地存储 SwpFMDB iOS本地持久化储存方式 iOS本地持久化储存方式,常用几种方式: NSUser...

  • iOS 本地化存储

    简介 iOS中常常会用到本地化存储,下面就总结一下常用的几种本地化存储方式 1. iOS数据存储的几种方式 Pre...

  • iOS 安全性参考点

    iOS本地数据存储安全 本地存储的方式主要有:Userdefault, 沙盒文件(包括DB文件),Archiev...

  • iOS开发之SQLite总结

    iOS本地持久化存储方式 NSUserDefaults:存储配置信息,适用小规模数据。NSUserDefaults...

  • 浅谈iOS本地存储

    iOS本地存储方式有很多种,比如:NSUserDefault,Plist文件存储,CoreData,解档与归档,沙...

  • ios 本地数据存储方式

    1)NSKeyedArchiver(归档)采用归档的形式来保存数据,该数据对象需遵守NSCoding协议,并且该对...

  • iOS本地数据持久化

    在iOS开发中常常需要将本地数据存储起来 通常有如下几种方式 plist存储 偏好设置存储 归档存储 SQLite...

  • 【iOS】数据持久化

    在iOS开发中我们常常需要做数据存储,这里主要说的时以下几种本地数据存储的方式。 NSUserDefaults属性...

  • iOS开发之数据存储以及删除

    iOS本地数据保存有多种方式,归纳如下: |保存到KeyChain(钥匙串)|存储为文件|存储到数据库||:-:|...

  • iOS五种本地缓存数据方式

    iOS本地缓存数据方式有五种: 1.直接写文件方式:可以存储的对象有NSString、NSArray、NSDict...

网友评论

    本文标题:ios本地存储的五种方式

    本文链接:https://www.haomeiwen.com/subject/jpnkbftx.html