你的位置:首页 > ASP.net教程

[ASP.net教程]iOS常用的几种数据存储方式


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

下面就简单介绍一下:

1.NSUserDefaults

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

NSUserDefaults支持的数据格式有:NSNumber(Integer、Float、Double),NSString,NSDate,NSArray,NSDictionary,BOOL类型

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

 //  测试数据  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(@"------%@----\n-----%@------",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:@"%@\n %ld\n %@",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];}

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

 

 

 

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