数据持久化

作者: Saxon_Geoffrey | 来源:发表于2015-03-07 19:41 被阅读410次

    这篇文章将会介绍数据持久化的4种方式:NSUserDefaults,NSFileManager,NSCoding+NSKeyedArchiver和CoreData

    1.NSUserDefaults

    Cocoa会为每个app自动创建一个文件,我们可以用它来存储一些较简单的数据,如音效等应用设置之类的少量信息。NSUserDefaults本质上是以Key-Value形式存成plist文件,放在/Library/Preferences/{Bundle Identifier}.plist目录下,这个文件是不安全的,所以不要用NSUserDefaults来存储密码之类的敏感信息

    NSUserDefaults是一个单例,它支持保存的数据类型有:NSNumber,NSString, NSDate, NSArray, NSDictionary, BOOL.

    1.写入数据

    // 获取一个NSUserDefaults对象
    NSUserDefaults * aUserDefaults = [NSUserDefaults standardUserDefaults];
    // 插入一个key-value值
    [aUserDefaults setObject:_label.text forKey:@"name"];
     
    // 同步操作,为了把设置及时写入文件,防止由于崩溃等情况App内存信息丢失
    [aUserDefaults synchronize];
    

    2.读取数据

    NSUserDefaults * aUserDefaults = [NSUserDefaults standardUserDefaults];
    // 获取一个key-value值
    NSString * aStr = [aUserDefaults objectForKey:@"name"];
    

    值得注意的是:NSUserDefaults存储的对象全是不可变的,例如,如果我想要存储一个 NSMutableArray对象,我必须先创建一个不可变数组:

    NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"123",@"234", nil];
    NSArray * array = [NSArray arrayWithArray:mutableArray];
         
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
    [user setObject:array forKey:@"name"];
    

    取出数据也一样:

    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
         
    NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:[user objectForKey:@"name"]];
    

    2. NSFileManager

    上面提到NSUserDefaults可以存成Plist文件,只是Apple帮我们封装好了读写方法而已(事实上我们自己实现这个方法也很简单)。NSUserDefaults的缺陷是存储只能是Library/Preferences/<Application BundleIdentifier>.plist 这个文件,如果我们要自己写一个Plist文件呢? 使用NSFileManger可以很容易办到。

    如果你存储的数据是Plist文件支持的类型,直接用NSFileManager的writToFile接口就可以写入一个plist文件了。Plist文件支持的数据格式有:NSString,NSNumber, Boolean, NSDate,NSData,NSArray和NSDictionary.其中,Boolean格式事实上以[NSNumber numberOfBool:YES/NO];这样的形式表示。

    1).获取路径:

    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    //Library目录路径:NSLibraryDirectory, Cache目录路径:NSCachesDirectory
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    //等同于以下操作
    //NSString * documentsPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    NSString *directoryPath = [documentsPath stringByAppendingPathComponent:@"file"];
    

    2).在上面的路径下创建目录:createDirectoryAtPath

    if (![fileManager fileExistsAtPath:directoryPath]) {
        [fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:NO attributes:nil error:nil];
    }]
    

    3).在上面的目录下创建文件:createFileAtPath

    [fileManager createFileAtPath:[documentsPath stringByAppendingString:@"/text.plist"] contents:data attributes:nil];
    
    //获取创建的该文件的路径
    filePath = [NSString stringWithFormat:@"%@%@",documentsPath,@"test.plist"];
    

    4).写数据到文件:writeToFile

    NSDictionary *dictionary = @{@"key":@"value"};
    dictionary writeToFile:filePath atomically:YES];
    

    5).读取文件的属性:attributesOfItemAtPath
    例如,读取文件的创建日期:

    NSDate *creationDate = nil;
    if ([fileManager fileExistsAtPath:filePath]) {
        NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:nil];
        creationDate = attributes[NSFileCreationDate];
    }
    

    6).删除文件:removeItemAtPath

    NSError *error = nil;
    if (![fileManager removeItemAtPath:filePath error:&error]) {
        NSLog(@"[Error] %@ (%@)", error, filePath);
    }
    

    3.NSKeyedArchiver/NSKeyedUnarchiver

    上面介绍的两种方法,通常仅支持常用数据类型,但是不支持自定义的数据类型,不过Cocoa提供了NSCoding和NSKeyArchiver两个工具类,可以把我们自定义的对象编码成二进制数据流,然后存进文件里面,如果要使用这种方式进行存储,首先自定义的对象要继承NSCoding的delegate。

    NSCoding是一个简单的协议,有两个方法:-initWithCoder: 和 encodeWithCoder:。遵循NSCoding协议的类可以被序列化和反序列化,这样可以归档到磁盘上或分发到网络上。

    @interface Book : NSObject <NSCoding>
    @property NSString *author;
    @property NSUInteger price;
    @end
    
    @implementation Book
    #pragma mark - NSCoding
    - (id)initWithCoder:(NSCoder *)decoder {
        self = [super init];
        if (!self) {
            return nil;
        }
        self.author = [decoder decodeObjectForKey:@"author"];
        self.price = [decoder decodeIntegerForKey:@"price"];
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)encoder {
        [encoder encodeObject:self.author forKey:@"author"];
        [encoder encodeInteger:self.price forKey:@"price"];
    }
    
    @end
    

    如上,NSCoding 主要是样板文件。每个属性用属性名作为key,编码或解码成一个对象或者类型。这样,我们就定义了一个可以使用NSCoding进行编码的数据对象。

    Mantle是一个意在减少写NSCoding样板文件的类库,可以看看)

    Archiving(归档):

    Book *books = [Book alloc] init];
    //归档至目录
    [NSKeyedArchiver archiveRootObject:books toFile:@"/path/to/archive"];
    //归档至二进制数据
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:books];
    

    Unarchiving(解档):

    //从目录解档
    [NSKeyedUnarchiver unarchiveObjectWithFile:@"/path/to/archive"];
    //从文件解档
    Book *book = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    

    除了归档到文件,还可以归档到NSUserDefaults。

    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:books];
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"books"];
    

    Unarchiving:

    NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"books"];
    NSArray *books = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    

    所以其实使用NSCoding和NSKeyedArchiver事实上也是写入和读取文件,只不过对复杂对象进行了编码使得文件支持更多数据类型而已。

    参考:Apple文档nshipsteriOS数据持久化

    下一节我们介绍CoreData

    相关文章

      网友评论

      • 三点水老木头:楼主,这篇文章的代码在哪里可以下载 ,下一篇文章中在github下载的应该是比较复杂的,求发份962369884@qq.com :smile:

      本文标题:数据持久化

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