• 数据存储与IO(二)


    一、NSBundle资源包。

    只要把文件拖到Xcode左边项目导航面板中,选择复制文件到项目中,该文件就包含进bundle中了。用[NSBundle mainBundle]获取应用程序包,常用的方法:

    • URLForResource:withExtension:根据资源名和扩展名获取对应的URL。
    • pathForResource:ofType:根据资源名和类型名获取对应的路径。
    • resourcePath:返回该NSBundle的子目录所包含资源的完整路径。

    二、NSKeyedArchiver 、NSKeyedUnarchiver归档和恢复。

    归档就是用某种格式把一个或多个对象保存到指定的文件中(把对象转化为可保存、可传输的数据流),在需要的时候再从文件中恢复它们(从数据流中恢复该对象)。

    NSKeyedArchiver和NSKeyedUnarchiver继承自NSCoder。

    1、NSKeyedArchiver的简单用法(适用于非自定义OC对象)。

    • 直接调用NSKeyedArchiver的archiveRootObject:toFile:类方法,指定一个对象为root进行归档。
      1 NSDictionary *dict = @{@"xiaohong" : @"小红", @"xiaoming" : @"小明"};
      2 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
      3 path = [path stringByAppendingPathComponent:@"dict.arch"];
      4 BOOL isSucc = [NSKeyedArchiver archiveRootObject:dict toFile:path];
    • 或者调用NSKeyedArchiver的archivedDataWithRootObject:类方法,把一个对象转换成NSData的类型并返回,再写入本地或网络。
      1 NSDictionary *dict = @{@"xiaohong" : @"小红", @"xiaoming" : @"小明"};
      2 NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dict];
      3 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
      4 path = [path stringByAppendingPathComponent:@"data.arch"];
      5 [data writeToFile:path atomically:YES];
    • 直接调用NSKeyedUnarchiver的unarchiveObjectWithFile:类方法进行恢复。
    • 1 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
      2 path = [path stringByAppendingPathComponent:@"dict.arch"];
      3 NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    • 或者调用NSKeyedUnarchiver的unarchiveObjectWithData:类方法,对已经归档成NSData的单对象进行恢复。
      1 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
      2 path = [path stringByAppendingPathComponent:@"data1.arch"];
      3 NSData *data = [NSData dataWithContentsOfFile:path];
      4 NSDictionary *dicts = [NSKeyedUnarchiver unarchiveObjectWithData:data];

    2、NSCoding协议的用法(适用于自定义OC对象)。

    如果程序需要归档或恢复任意自定义对象,则该类必需实现NSCoding协议,并实现协议中定义的方法。

    • 1 #import <UIKit/UIKit.h>
      2 
      3 @interface HLPerson : NSObject <NSCoding>
      4 
      5 @property (copy, nonatomic) NSString *name;
      6 @property (assign, nonatomic) CGFloat height;
      7 
      8 @end
    • 归档该对象时,总会调用encodeWithCoder:方法,在此方法中分别调用NSCoder的encodeXxx:forKey:方法归档对应的成员变量。
    • 回复该对象时,总会调用initWithCoder:方法,在此方法中分别调用NSCoder的decodeXxxForKey:方法恢复对应的成员变量的值。
       1 #import "HLPerson.h"
       2 
       3 @implementation HLPerson
       4 
       5 - (void)encodeWithCoder:(NSCoder *)aCoder {
       6     [aCoder encodeObject:self.name forKey:@"name"];
       7     [aCoder encodeFloat:self.height forKey:@"height"];
       8 }
       9 
      10 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
      11     self.name = [aDecoder decodeObjectForKey:@"name"];
      12     self.height = [aDecoder decodeFloatForKey:@"height"];
      13     return self;
      14 }
      15 
      16 @end

    然后就可以像归档普通对象一样归档我们自定义的HLPerson对象了,参看1。

    3、用NSData自定义归档。

    前面的方法只能归档或恢复单个的OC对象,若要归档或恢复多个对象到单个文件中,则可以借助NSMutableData来创建NSKeyedArchiver或者NsKeyedUnarchiver对象。

    (1)、归档步骤。

    • 创建一个NSMutableData对象,并以此对象为参数调用initForWritingWithMutableData创建NSKeyedArchiver对象。
    • 重复调用NSKeyedArchiver对象的encodeXxx:forKey:方法来归档所有需要归档到一个文件中的对象。
    • 调用NSKeyedArchiver对象的finishEncoding方法结束归档。
    • 保存该NSMutableData对象到本地或网络。
       1 HLPerson *person = [[HLPerson alloc] init]; // 自定义的对象需实现NSCoding协议
       2 person.name = @"hahh";
       3 person.height = 55;
       4 
       5 NSDictionary *dict = @{@"xiaohong" : @"小红", @"xiaoming" : @"小明"};
       6 NSArray *array = @[person, dict];
       7 CGFloat age = 12.5;
       8 
       9 NSMutableData *data = [NSMutableData data];
      10 NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
      11 [arch encodeObject:person forKey:@"person"];
      12 [arch encodeObject:dict forKey:@"dict"];
      13 [arch encodeObject:array forKey:@"array"];
      14 [arch encodeFloat:age forKey:@"age"];
      15 [arch finishEncoding];
      16 
      17 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
      18 path = [path stringByAppendingPathComponent:@"data.arch"];
      19 BOOL isSucc = [data writeToFile:path atomically:YES];

    (2)、恢复步骤。

    • 以NSData为参数创建NSKeyedUnarchiver对象。
    • 重复调用NSKeyedUnarchiver对象的decodeXxx:forKey:方法来从一个文件中恢复所有归档过的对象。
    • 调用NSKeyedUnarchiver对象的finishEncoding方法结束恢复。
       1 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
       2 path = [path stringByAppendingPathComponent:@"data.arch"];
       3 NSData *data = [NSData dataWithContentsOfFile:path];
       4 NSKeyedUnarchiver *unarch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
       5 
       6 HLPerson *person = [unarch decodeObjectForKey:@"person"];
       7 NSDictionary *dict = [unarch decodeObjectForKey:@"dict"];
       8 NSArray *array = [unarch decodeObjectForKey:@"array"];
       9 CGFloat age = [unarch decodeFloatForKey:@"age"];
      10 
      11 [unarch finishDecoding];

    延伸:归档会将整个对象转换成字节数据,包括该对象的所有成员变量,如果该成员变量指向另一个OC对象,则此OC对象也将一起被归档成字节数据。这就表明:当归档一个对象时,系统会把该对象关联的所有数据,都转换为字节数据。如果程序从这些字节数据中恢复对象,则恢复出来的对象和原来的对象相同,但在内存上的地址不同,这就实现了对象的深复制。

    三、NSUserDefaults

    NSUserDefaults是一个单例类,一般用来保存程序参数、用户账号、选项相关的少量数据,用它存储的对象放在沙盒的Library/Preferences目录下的文件中。

    1、存储OC类型的对象:

    • standardUserDefaults:获取该单例对象。
    • setXxx:forKey:根据key设置要存储的对象。

    • synchronize:保存对象到Library/Preferences目录下的文件中。

    • xxxForKey:根据key获取对应的对象。
      1 NSDictionary *dict1 = @{@"xiaohong" : @"小红", @"xiaoming" : @"小明"};
      2 CGFloat height = 111.1;
      3 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      4 [defaults setObject:dict1 forKey:@"dict1"];
      5 [defaults setFloat:height forKey:@"height"];
      6 [defaults synchronize];
      7 NSDictionary *dict2 = [defaults objectForKey:@"dict1"];
      8 NSLog(@"%@ ---- %@ ---- %.2f", dict2[@"xiaohong"], dict2[@"xiaoming"], height);

    NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,NSData,BOOL。存储的对象全是不可变的。

    2、存储自定义类型的对象:

    NSUserDefaults不支持自定义对象,可以把自定义对象转成NSData类型进行存储:

    • 自定义的类需遵守NSCoding协议,且实现协议方法:encodeWithCoder:和initWithCoder:。
    • 第一种方法是:调用NSKeyedArchiver的archivedDataWithRootObject:类方法,把一个对象转换成NSData的类型并返回。第二中方法是:创建一个NSMutableData对象,并以此对象为参数调用initForWritingWithMutableData创建NSKeyedArchiver对象,重复调用NSKeyedArchiver对象的decodeObjectForKey:forKey:方法来归档所有需要归档到一个文件中的对象,调用NSKeyedArchiver对象的finishEncoding方法结束归档。
    • 调用NSUserDefaults的setObject:dict1 forKey:存储上一步骤得到的NSData或NSMutableData对象。(参考本篇二)

    恢复对象:

    • 调用NSUserDefaults的objectForKey:取出对应的NSData对象。
    • 第一种方法是:调用NSKeyedUnarchiver的unarchiveObjectWithData:类方法,对已经归档成NSData的对象进行恢复。第二中方法是:以上一步得到的NSData对象为参数创建NSKeyedUnarchiver对象,重复调用NSKeyedUnarchiver对象的decodeObject:forKey:方法来从一个文件中恢复所有归档过的对象,调用NSKeyedUnarchiver对象的finishEncoding方法结束恢复。(参考本篇二)

    注:对相同的key进行赋值,相当于覆盖原有的值。

    四、属性列表

    属性列表适合保存少量简单的数据,Xcode能以图形化的方式来编辑属性列表文件。

    • writeToFile:atomically:把目标对象写入文件。
    • xxxWithContentsOfFile:初始化对象。
       1 NSDictionary *dict1 = @{@"xiaohong" : @"小红", @"xiaoming" : @"小明"};
       2 NSDictionary *dict2 = @{@"xiaogong" : @"小刚", @"xiaoqiang" : @"小强"};
       3 NSArray *array1 = @[dict1, dict2];
       4 
       5 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
       6 path = [path stringByAppendingPathComponent:@"data.plist"];
       7 [array1 writeToFile:path atomically:YES];
       8 
       9 NSArray *array2 = [NSArray arrayWithContentsOfFile:path];
      10 NSLog(@"%@ ---- %@ ---- %@ ---- %@", [array2[0] objectForKey:@"xiaohong"], [array2[0] objectForKey:@"xiaoming"], [array2[1] objectForKey:@"xiaogong"] ,[array2[1] objectForKey:@"xiaoqiang"]);

    属性列表只能保存下列类型的对象:NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSData、NSMutableData、NSString、NSMutableString、NSValue和NSNumber。

    如果需要保存自定义的对象,可以使用对象归档的方式,详见二。

    五、SQLite3

    详见SQLite3的基本使用

    六、Core Data 

    详见Core Data的一些常见用法

    七、FMDB

    详见FMDB的简单使用

     

  • 相关阅读:
    什么是基于注解的容器配置?
    一个线程运行时发生异常会怎样?
    Java 中你怎样唤醒一个阻塞的线程?
    为什么 wait, notify 和 notifyAll 这些方法不在 thread 类里面?
    Java 中 notify 和 notifyAll 有什么区别?
    在 Spring MVC 应用程序中使用 WebMvcTest 注释有什么用处?
    java 中有几种方法可以实现一个线程?
    什么是AOP?
    什么是竞争条件?你怎样发现和解决竞争?
    Mybatis 是如何进行分页的?分页插件的原理是什么?
  • 原文地址:https://www.cnblogs.com/hankkk/p/5731627.html
Copyright © 2020-2023  润新知