美文网首页工作中用到的好技术
IOS 数据储存五个方案

IOS 数据储存五个方案

作者: 汤姆杰瑞 | 来源:发表于2020-08-16 22:54 被阅读0次
    IOS储存的五个方案

    1. NSUserDefaults (偏好设置文件)
    2. plist文件
    3. 归档 (反归档)
    4. SQLite3(FMDB)
    5. CoreData

    沙盒中相关路径 介绍
    - AppName.app 应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以不能在运行时对这个目录中的内容进行修改,否则会导致应用程序无法启动。
    - Documents/ 保存应用程序的重要数据文件和用户数据文件等。用户数据基本上都放在这个位置(例如从网上下载的图片或音乐文件),该文件夹在应用程序更新时会自动备份,在连接iTunes时也可以自动同步备份其中的数据。
    - Library:这个目录下有两个子目录,可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹,除Caches以外,都会被iTunes备份.
    -   Library/Caches: 保存应用程序使用时产生的支持文件和缓存文件(保存应用程序再次启动过程中需要的信息),还有日志文件最好也放在这个目录。iTunes 同步时不会备份该目录并且可能被其他工具清理掉其中的数据。
    -   Library/Preferences: 保存应用程序的偏好设置文件。NSUserDefaults类创建的数据和plist文件都放在这里。会被iTunes备份。
    - tmp/: 保存应用运行时所需要的临时数据。不会被iTunes备份。iPhone重启时,会被清空。
    
    
    1. NSUserDefaults
    NSUserDefaults 介绍
    
    - 在运行时,您使用对象从用户的默认数据库中读取应用程序使用的默认值。缓存信息,以避免每次需要默认值时都必须打开用户的默认数据库。设置默认值时,它将在您的流程中同步更改,并异步更改为持久性存储和其他流程。
    - NSUserDefaults 默认对象必须是一个属性列表,也就是说,的一个实例(或对集合的实例的组合)NSData,NSString,NSNumber,NSDate,NSArray,或NSDictionary。如果要存储任何其他类型的对象,通常应将其归档以创建NSData的实例。
    - NSUserDefaults用来存储 用户设置 系统配置等一些小的数据。因为数据是明文存储在 plist 文件中,不安全,即使只是修改一个 key 都会 load 整个文件,数据多加载慢( 内存),不适合存储大量数据。
    - 它是单例,也是线程安全的,是以键值对 key-value 的形式保存在沙盒中
    - 沙盒路径为 Library/Preferences。文件格式为 .plist
    - NSUserDefaults返回的值是不可改变的,即使存储的时候是可变的值。对相同的Key赋值约等于一次覆盖。
    
    
    //NSUserDefaults
    //setObject中的key和value可以为除了nil外的任何对象
    //setValue中的key只能为字符串 value可以为nil也可以为空对象[NSNull null]以及全部对象
    NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    [userDefault setObject:@"小明" forKey:@"name"];
    //app意外退出或者中断,数据不会被系统写入所以命令synchronize直接同步到文件里,来避免数据的丢失。
    [userDefault synchronize]; 
    
    //取出对应的Key也就是name
    [userDefault objectForKey:@"name"];
    
    NSLog(@"name = %@",[userDefault objectForKey:@"name"]);
    //打印  name = 小明
    
    2. plist文件
    plist文件 介绍
    
    - plist的文件名不能单独命名做"info"、"Info"之类的,是因为与系统属文件重名
    - 属性列表是一种XML格式的文件,拓展名为plist
    - 对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中
    - Plist不能存储自定义对象,成功后会写入到Documents文件中(app)
    - xcode中plist文件创建步骤:NewFile —— IOS —— Resource —— Property List
    
    
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:@"newInfo.plist"];
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:@"小红" forKey:@"name"];
    [dict setObject:@"18" forKey:@"age"];
    [dict writeToFile:filePath atomically:YES];
        
    NSDictionary *dics = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"age:%@", [dics objectForKey:@"age"]);
    
    newInfo.plist
    3. 归档 (反归档)
    归档 (反归档) 介绍
    -之前将数据存储到本地,只能是字符串、数组、字典、NSNuber、BOOL等容器类对象,不能将自定义对象进行保存,而通过归档能将所有的对象转化为二进制数据存储到文件中。
    - 什么是归档
    1.字典,数组,自定义的对象等在存储时需要转换为字节流NSData类型数据,再通过写入文件来进行存储。
    - 什么是反归档
    2.字节流转换为字典,数组,自定义的类等
    - 归档的缺点
    3.归档保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据,而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据。
    - 归档的使用场景
    4.有些应用没联网时,可以将手机有网时的数据存放在本地,没网时,从本地中取出来这些数据展示。
    
    
    //Students.h 文件
    #import "Students.h"
    //遵循NSCoding协议
    @interface Students : NSObject<NSCoding>
    
    @property (nonatomic,copy) NSString *name;
    @property (nonatomic,assign) NSInteger age;
    
    //Students.m 文件
    #import "Students.m"
    //需要重写两个协议方法
    //-(void)encodeWithCoder:(NSCoder *)aCoder方法:
    //-(id)initWithCoder:(NSCoder *)aDecoder方法:
    
    // 当将一个自定义对象保存到文件的时候就会调用该方法
    // 在该方法中说明如何存储自定义对象的属性
    // 也就说在该方法中说清楚存储自定义对象的哪些属性
    -(void)encodeWithCoder:(NSCoder *)aCoder
    {
      NSLog(@"调用了encodeWithCoder:方法");
      [aCoder encodeObject:self.name forKey:@"name"];
      [aCoder encodeInteger:self.age forKey:@"age"];
     }
    
    // 当从文件中读取一个对象的时候就会调用该方法
    // 在该方法中说明如何读取保存在文件中的对象
    // 也就是说在该方法中说清楚怎么读取文件中的对象
    -(id)initWithCoder:(NSCoder *)aDecoder
    {
      NSLog(@"调用了initWithCoder:方法");
         //注意:在构造方法中需要先初始化父类的方法
         if (self=[super init]) {
          self.name=[aDecoder decodeObjectForKey:@"name"];
          self.age=[aDecoder decodeIntegerForKey:@"age"];
         }
         return self;
     }
    //ViewController.h 文件
    #import "ViewController.h"
    
    Students *stu = [[Students alloc]init];
    stu.name = @"掰掰";
    stu.age = 8;
    // 获取文件路径
    NSString *docPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *path = [docPath stringByAppendingPathComponent:@"Students.archiver"];
    //进行归档
    [NSKeyedArchiver archiveRootObject:stu toFile:path];
    //反归档
    Students *s1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path] ;
    NSLog(@"---------%@", s1.name);//掰掰
    NSLog(@"---------%ld", (long)s1.age);//8
    

    采用多个对象储存

    - (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);
    }
    
    4. SQLite3
    数据库(splite):
    splite是一个轻量级,跨平台的小型数据库,可移植性比较高,有着和MySpl几乎相同的数据库语句,以及无需服务器即可使用的优点:
    
    数据库的优点:
    
    存储大量的数据,存储和检索的速度非常快.
    能对数据进行大量的聚合,这样比起使用对象来讲操作要快.
    数据库的缺点:
    
    它没有提供数据库的创建方式
    它的底层是基于C语言框架设计的, 没有面向对象的API, 用起来非常麻烦
    发杂的数据模型的数据建表,非常麻烦
    在实际开发中我们都是使用的是FMDB第三方开源的数据库,该数据库是基于splite封装的面向对象的框架.
    
    
        //sqlite3
        //1.获取沙盒文件名
      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(@"打开数据库失败");
        }
    
    
    //sqlite3 添加数据库
    - (IBAction)AddSqlite3:(UIButton *)sender {
     
        for (int i = 0; i < 10; i++) {
            
            NSString *name = [NSString stringWithFormat:@"小明-%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)sqlite3delete:(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)sqliteUpdate:(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(@"更改失败");
        }
        
    }
    
        
    
    5. CoreData
    CoreData核心类与结构
    
    NSManagedObjectContext(数据上下文)
    
    对象管理上下文,负责数据的实际操作(重要)
    作用:插入数据,查询数据,删除数据,更新数据
    NSPersistentStoreCoordinator(持久化存储助理)
    
    相当于数据库的连接器
    作用:设置数据存储的名字,位置,存储方式,和存储时机
    NSManagedObjectModel(数据模型)
    
    数据库所有表格或数据结构,包含各实体的定义信息
    作用:添加实体的属性,建立属性之间的关系
    操作方法:视图编辑器,或代码
    NSManagedObject(被管理的数据记录)
    
    数据库中的表格记录
    NSEntityDescription(实体结构)
    
    相当于表格结构
    NSFetchRequest(数据请求)
    
    相当于查询语句
    后缀为.xcdatamodeld的包
    
    里面是.xcdatamodel文件,用数据模型编辑器编辑
    编译后为.momd或.mom文件
     
    

    参考博客链接

    相关文章

      网友评论

        本文标题:IOS 数据储存五个方案

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