• iOS常用的几种数据存储方式


    之前由于刚入行不久,对数据持久化不是很了解,尤其是用数据库存储大量数据的操作。经过摸索就在此总结一下,方便以后查阅

    下面就简单介绍一下:

    1.NSUserDefaults

    感觉最常用的小量数据,属性,例如,账号,密码之类的;适合存储轻量级的本地数据 (个人认为这种比较简单)

    NSUserDefaults支持的数据格式有:NSNumberIntegerFloatDouble),NSStringNSDateNSArrayNSDictionaryBOOL类型

    直接看代码比较容易理解:

     //    测试数据
        NSArray *myArray = [NSArray arrayWithObjects:@"hello", @"world", nil];
        NSDictionary *myDictionary = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"enuo", @"20", nil] forKeys:[NSArray arrayWithObjects:@"name", @"age", nil]];
        //    存入
        [[NSUserDefaults standardUserDefaults] setObject:myArray forKey:@"arry"];
        [[NSUserDefaults standardUserDefaults] setObject:myDictionary forKey:@"dict"];
        
        //这里建议同步存储到磁盘中,但是不是必须的
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        //    读取
        NSArray *arr= [[NSUserDefaults standardUserDefaults] objectForKey:@"arry"];
        NSDictionary *dict = [[NSUserDefaults standardUserDefaults] objectForKey:@"dict"];
        NSLog(@"------%@----
    -----%@------",arr,dict);
        
        
        // 清除数据
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"keyName"];

    建议:[NSUserDefaults standardUserDefaults] 可以在项目中定义一个全局的宏,这样使用起来更便捷。


    2.归档

    目的是为了长时间存放有组织的数据集

    (1)简单的归档方式 但是只能存储单个对象。

     //    (1)归档
        NSArray *array = [NSArray arrayWithObjects:@1,@2,@3, nil];
        NSString *filePath = [NSHomeDirectory() stringByAppendingString:@"testFile.plist"];
        BOOL success = [NSKeyedArchiver archiveRootObject:array toFile:filePath];
        
        NSLog(@"%d",success);
        NSLog(@"%@",filePath);
        
        //    (2)反归档
        NSString *filePath = [NSHomeDirectory() stringByAppendingString:@"testFile.plist"];
        id OUTarray = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
        NSLog(@"%@",OUTarray);
        

    (2)可以将多个对象归档成一个文件。

     //    (1)归档
        NSMutableArray *arrayArchiver = [NSMutableArray arrayWithObjects:@"BigDragon",@"BigBiao",@"BigBaby", nil];
        NSMutableData *data = [NSMutableData data];
        
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
        //编码
        [archiver encodeObject:arrayArchiver forKey:@"array"];
        [archiver encodeObject:@"Jason‘s friends" forKey:@"name"];
        
        //编码完成之后,对象已经存储到data之中。
        [archiver finishEncoding];
        
        NSString *filePathtwo = [NSHomeDirectory() stringByAppendingPathComponent:@"arraytwo.plist"];
        BOOL successtwo = [data writeToFile:filePathtwo atomically:YES];
        NSLog(@"------%d",successtwo);
        
        
        //    (2)反归档
        
        NSString *filePathtwo = [NSHomeDirectory() stringByAppendingPathComponent:@"arraytwo.plist"];
        //读取归档数据
        NSData *dataUnarchiver = [[NSData alloc] initWithContentsOfFile:filePathtwo];
        
        //创建解归档对象,进行反归档
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:dataUnarchiver];
        
        //反归档
        NSArray *arrayUnarchiver = [unarchiver decodeObjectForKey:@"array"];
        NSLog(@"----%@",arrayUnarchiver);
        
        NSString *nameUnarchiver = [unarchiver decodeObjectForKey:@"name"];
        NSLog(@"-----%@",nameUnarchiver);

    (3)使用工具类(感觉如果使用归档,一般使用工具类,相对来说便捷一点)

    下面就先建个工具类;Person类

    Person.h

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject<NSCoding>  //需要遵守NSCoding协议
    
    @property (nonatomic,strong) NSString *name; //带归档类型
    @property (nonatomic,assign) NSInteger age;
    @property (nonatomic,strong) NSString *gender;
    
    - (NSString *)description;
    @end

    Person.m

    /**
     该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。前一个方法告诉系统怎么对对象进行编码,而后一个方法则是告诉系统怎么对对象进行解码
     */
    
    // 归档方法
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        [aCoder encodeObject:self.name forKey:@"name"];
        [aCoder encodeInteger:self.age forKey:@"age"];
        [aCoder encodeObject:self.gender forKey:@"gender"];
    }
    // 反归档方法
    - (instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        self = [super init];
        
        if (self != nil) {
            self.name = [aDecoder decodeObjectForKey:@"name"];
            self.age = [aDecoder decodeIntegerForKey:@"age"];
            self.gender = [aDecoder decodeObjectForKey:@"gender"];
        }
        return self;
    }
    
    - (NSString *)description
    {
        NSString *string = [NSString stringWithFormat:@"%@
     %ld
     %@",self.name,self.age,self.gender];
        return string;
    }

     在控制器用的时候:

        Person *person = [[Person alloc]init];
        
        person.name = @"rose";
        person.age = 25;
        person.gender = @"man";
        
        // 归档,调用归档方法
        NSString *filePath3 = [NSHomeDirectory() stringByAppendingString:@"person.plist"];
        BOOL success3 = [NSKeyedArchiver archiveRootObject:person toFile:filePath3];
        NSLog(@"=====%d",success3);
        
        // 反归档,调用反归档方法
        Person *per = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath3];
        NSLog(@"=======%@",per);

    3.写入文件

    主要的步骤:

        //第一步:获得文件即将保存的路径:(永久保存在磁盘中)
        //    文件存储的相对目录
        NSArray *filePaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString*path = filePaths.firstObject;
        
        //第二步:生成在该路径下的文件:
        NSString *FileName=[path stringByAppendingPathComponent:@"flieName"];//fileName就是保存文件的文件名
      
    // 第三步:往文件中写入数据:
    NSData *data; [data writeToFile:FileName atomically:YES];//将NSData类型对象data写入文件,文件名为FileName
    // 最后:从文件中读出数据: NSData *outdata=[NSData dataWithContentsOfFile:FileName options:0 error:NULL];//从FileName中读取出数据

    下面就简单的举几个例子

    #pragma mark--1.字符串写入
        //    NSString *strfilepath = [path stringByAppendingPathComponent:@"str.text"];
        NSString *strfilepath = [path stringByAppendingString:@"/text.text"];
        NSString *INstr = @"字符串写入文件";
        [INstr writeToFile:strfilepath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        
        //    读取文件
        NSString *OUTstr  = [[NSString alloc]initWithContentsOfFile:strfilepath encoding:NSUTF8StringEncoding error:nil];
        NSLog(@"----%@-----",OUTstr);
        
        
    #pragma mark-2、数组对象写入文件
        //    构造数组plist文件的存储路径
        NSString*arrypath = [path stringByAppendingPathComponent:@"arry.plist"];
        NSArray *INarr = @[@"hahah",@"hehhe",@"heihei"];
        [INarr writeToFile:arrypath atomically:YES];
        
        //    读取文件
        NSArray *outarr =  [[NSArray  array]initWithContentsOfFile:arrypath];
        NSLog(@"----%@-----",outarr);
        
        
    #pragma mark-3、字典对象写入文件
        NSString*dictpath = [path stringByAppendingPathComponent:@"dict.plist"];
        NSDictionary *dict = @{@"姓名":@"liuwenqiang",@"年龄":@"25",@"职业":@"ios"};
        [dict writeToFile:dictpath atomically:YES];
        
        //    读取文件
        NSDictionary *OUTdict =  [[NSDictionary  alloc]initWithContentsOfFile:dictpath];
        NSLog(@"----%@-----",OUTdict);
        
        
        
    #pragma mark-4、二进制对象写入文件
        NSString *datapath = [path stringByAppendingPathComponent:@"song.m4a"];
        UIImage *image = [UIImage imageNamed:@"image"];
        NSData *imagedata = UIImageJPEGRepresentation(image, 1);
        [imagedata writeToFile:datapath atomically:YES];
        
        //    读取文件
        NSData *OUTdata =  [[NSData  alloc]initWithContentsOfFile:datapath];
        NSLog(@"----%@-----",OUTdata);
        

    4.数据库

    对于大型的数据存储,再使用上面的方法显然不适用了,该使用数据库了,我在项目中使用的是第三方的数据库FMDB,个人感觉比较好用,使用比较顺手。

    那么什么是大型数据,我认为的就是那种像app里的列表之类的,由于列表的数据量相当比较大,如果像我们的应用,列表中还有列表图的话,那就更大了。

    当初在看数据库之前,总感觉很难理解,不好学,但是慢慢的理解了,也并不是那么难理解,(下面的方法是需要在工具类的.h中声明的,这样控制器中才能调到)

    在操作之前,需要先下载一个FMDB 拉到项目中    附上: FMDB下载地址

    先创建一个工具类 fmbdTool

    (1)创库建表 

    @implementation FmdbTool
    
    {
        FMDatabase *db;
    }
    -(NSString*)createFMDBTable:(NSString *)type
    {
        NSString *str;
        //1.获得数据库文件的路径
        NSString *doctorpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        
        NSString *filePath =  [doctorpath stringByAppendingPathComponent:@"doctor.sqlite"];
    //    NSLog(@"-------路径----%@-------",filePath);
        //2.获得数据库
        db = [FMDatabase databaseWithPath:filePath];
        //3.打开数据库
        if ([db open]) {
            //4.创表
            BOOL result;
            if ([type isEqualToString:@"doctor"]) {
        
                result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_doctor (id integer PRIMARY KEY AUTOINCREMENT,doctordict blob NOT NULL,page_ID integer NOT NULL,datacount text NOT NULL)"];
                
            }
            
            if (result) {
    //            NSLog(@"====建表成功--------type=== %@",type);
                
                str = @"yes";
                
            }else
            {
                NSLog(@"====建表失败");
                str = @"no";
            }
        }else {
            NSLog(@"faile to create a FMDB");
            str = @"no";
        }
        
        return str;
    }

    在我的项目中,由于有很多的列表要做数据存储,因此我在创建库的方法中加了一个参数type,为每个要存储的页面都建一张表,并把所有的表都放到

    doctor.sqlite这个库中。
    在创建表的时候,首先要[db open]打开数据库,该返回数据类型是bool,当为真的时候,再创建表
     result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_doctor (id integer PRIMARY KEY AUTOINCREMENT,doctordict blob NOT NULL,page_ID integer NOT NULL,datacount text NOT NULL)"];
    doctordict是个数字类型的数据,就是像后台返回的下面数据中,doctorInfoList字段,所以doctordict的类型是blob 。并且由于该字段不可能为空,故在建表的时候 NOT NULL 。
    列表做了分页请求,所以在表中把页码存储了,page_ID integer NOT NULL。 datacount是列表总的页数。

    
    

    (2)插入数据

    //插数据
    -(void)addDataInsetTable:(NSArray *)doctorListArry page:(NSInteger)page datacount:(NSString*)datacount type:(NSString *)type
    {
        if ([db open]) {
            
            NSString *pagestr = [NSString stringWithFormat:@"%ld",(long)page];
            NSError *err = nil;
            
            NSData *jsonData  = [NSJSONSerialization dataWithJSONObject:doctorListArry options:NSJSONWritingPrettyPrinted error:&err];
            
            NSString *jsonStr = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
            
            if ([type isEqualToString:@"doctor"]) {
                
                [db executeUpdate:@"INSERT INTO t_doctor (doctordict,page_ID,datacount) VALUES (?,?,?);",jsonStr,pagestr,datacount];
                
            }
                
        }
        [db open];
    
    }

    插入数据是也是 先[db open]之后才能插入数据。

    通过这个方法可以看出,我直接就可以把后台返回给我的数据,responseObject[@"doctorInfoList"] 插到表中,

    在插入之前,需要先把数组转成json类型的字符串,我在这里使用了,JSONKit    JSONKit下载地址

    (3).取数据

    -(NSArray *)outdata:(NSString *)type
    {
        NSArray *dataArr;
        
        NSMutableArray  *aaarr = [[NSMutableArray alloc]init];
        if ([db open]) {
        
            if ([type isEqualToString:@"doctor"]) {
                FMResultSet  *res = [db executeQuery:@"SELECT * FROM t_doctor"];
                
                while (res.next) {
                    
                    NSString *s = [res stringForColumn:@"doctordict"];
                    
                    NSArray *aa = [s objectFromJSONString];
                    
                    [aaarr addObjectsFromArray:aa];
                    dataArr = aaarr;
                    
                }
                
            }
        }
        
        [db close];
    
        return dataArr;
    }
    //取出当前页数 在该type时
    -(NSString *)checkoutpage:(NSString *)type
    {
        NSString *str;
        if ([db open]) {
        
                FMResultSet *res = [db executeQuery:@"SELECT * FROM t_activesecond where type = ?",type];
                
                while (res.next)
                {
                    str = [res stringForColumn:@"page"];
            }
        }
        [db close];
        
        return str;
    }

    (4).删除数据

    //删除数据
    - (void)deleteData:(NSString *)type
    {
    
        if ([db open]) {
            
            if ([type isEqualToString:@"doctor"]) {
                NSString *deleteSql = [NSString stringWithFormat:@"delete from t_doctor"];
                [db executeUpdate:deleteSql];
                
            }
        }
        
        [db close];
    }

    我在删除数据的时候,只删除了,指定表,并没有直接把库删了,因为所以的表都在这个库里。

    先写到这吧,如果哪里说错了,请指出,谢谢啦。



  • 相关阅读:
    JS搞基指南----延迟对象入门提高资料整理
    JavaScript使用自定义事件实现简单的模块化开发
    nodeJS+bootstarp+mongodb整一个TODO小例子
    nodeJS+express+Jade写一个局域网聊天应用(node基础)
    jQ1.5源码注释以及解读RE
    jQ1.5中的事件系统(低版本的事件系统)
    JS中的事件类型和事件属性的基础知识
    [转][mysql]创建函数失败(1418错误)mysql双主模式导致的问题
    MySQL数据库导入错误:ERROR 1064 (42000) 和 ERROR at line xx:
    Vmware由于centos升级内核不可运行(C header files matching your running kernel were not found)的解决方案
  • 原文地址:https://www.cnblogs.com/liuwenqiang/p/5548188.html
Copyright © 2020-2023  润新知