美文网首页程序员
编码篇-持久化NSUserDefaults

编码篇-持久化NSUserDefaults

作者: 進无尽 | 来源:发表于2017-11-27 20:06 被阅读0次

前言

NSUserDefaults类,以字典形式保存数据,IOS会自动把字典中的键值对转换成对应的XML文件(也就是plist文件),这个文件会被保存到APP的沙盒目录中(路径为Library/Preferences/plist文件名)。

NSUserDefaults为我们封装了读写plist文件的常用操作,我们可以使用它来保存一些简单的数据,比如系统配置,用户设置的参数之类的。

获取当前沙盒的Documents路径
  NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
查看当前沙盒文件
A文件内容
说明:上图中A(Bundle identifier.plist)是系统自动为我们创建的plist文件用来保存我们使用NSUserDefaults保存的数据。B为我们自己创建的的 plist文件,默认是在 Documents下。

值得注意的地方

  • NSUserDefault 支持的存储类型有:NSString、 NSNumber、NSDate、 NSArray、NSDictionary、BOOL、NSInteger、NSFloat等系统定义的数据类型以及他们的子类。

  • 自己创建的类 是不识别的 。

  • 字典中有 "<null>"这样的数据在使用NSUserDefault储存时会造成崩溃。
    Attempt to insert non-property list object 报错原因,

  • 从NSUserDefaults返回的值是不可改变的,即便是你在存储的时候使用的是可变的值。例如你使用mutable string做为“MyStringDefault”的值,当你做使用stringForKey:方法获取的值,这个值仍然是不可变的。

  • NSUserDefaults是单例,同时也是线程安全的

NSUserDefaults 的使用

简便方法存取不同类型数据
由上边的例子可以看到一个方法-setInteger:,这跟常用的-setObject:相比设置类型更明确。其实,NSUserDefaults提供了若干简便方法可以存储某些常用类型的值,例如:

- setBool:forKey:
 - setFloat:forKey:
- setInteger:forKey:
 - setDouble:forKey:
  - setURL:forKey:
这将使某些值的设置更简单。

NSUserDefaults 常规使用方法封装

- (void)setUserDefaults :(id)obj :(NSString*)key;
{
    if (!obj) {
        return;
    }
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
    [[NSUserDefaults standardUserDefaults] setObject:obj forKey:key];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
- (id)getUserDefaults :(NSString*)key;
{
    return [[NSUserDefaults standardUserDefaults]objectForKey:key];
}
- (void)removeOneDefaults :(NSString *)key;
{
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
     [[NSUserDefaults standardUserDefaults] synchronize];
}

打印出系统中所有的 NSUserDefaults设置

NSDictionary* defaults = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
NSLog(@"Defaults: %@", defaults);

registerDefaults方法的使用

- (void)registerDefaults:方法来初始化,这个方法会检查 NSUserDefaults是否已经存在了相同的key,如果存在就不会将其覆盖(相当于什么也没做),如果不存在就做保存操作。

简单举例来说明一下:

1.当第一次运行app时初始化了@"color":@"blue"
[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"color":@"blue"}];
这时NSUserDefaults里面'color'=='blue';

2.如果你在app中又重新设置了'color'=='red';

3.这时你重新运行一下你的app,仍然会调用[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"color":@"blue"}];;但是此时,它检测到color这个key已经存在,并且'color'=='red',
  就不将blue写入NSUserDefaults中。此时依然是'color'=='red';

储存自定义对象

使用归档存储(真的储存)

一个NSUserDefaults的对象必须是属性表,这也就是说我们可以存储NSData,NSString,NSNUmber,NSDate,NSArray,NSDictionary这些实例。如果你想存储其他类型的对象,我们可以将其归档并创建一个NSData来实现存储。

让这个自定义类实现<NSCoding>协议中的
- (id) initWithCoder: (NSCoder *)coder方法和
- (void) encodeWithCoder: (NSCoder *)coder方法
然后把该自定义的类对象编码到NSData中,再从NSUserDefaults中进行读取。

#import <Foundation/Foundation.h>

@interface Test : NSObject
<NSCoding>
@property(copy,nonatomic)NSString *imageName;
@property(copy,nonatomic)NSString *ageStr;
@end

#import "Test.h"
@implementation Test
- (id) initWithCoder: (NSCoder *)coder
{
    if (self = [super init])
    {
        self.imageName = [coder decodeObjectForKey:@"imageName"];
        self.ageStr = [coder decodeObjectForKey:@"ageStr"];
    }
    return self;
  }
  - (void) encodeWithCoder: (NSCoder *)coder
  {
    [coder encodeObject:self.imageName forKey:@"imageName"];
    [coder encodeObject:self.ageStr forKey:@"ageStr"];
  }

@end

使用NSUserDefaults 储存

Test *bc = [[Test alloc] init];
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSData *udObject = [NSKeyedArchiver archivedDataWithRootObject:bc];
[ud setObject:udObject forKey:@"myBusinessCard"];
udObject = [ud objectForKey:@"myBusinessCard"];
bc = [NSKeyedUnarchiver unarchiveObjectWithData:udObject];

储存 NSDictionary 后赋值给对象(假储存)

- (void)saveSchoolInfo:(NSDictionary *)info {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  [userDefaults setObject:info forKey:@"school"];
  [userDefaults synchronize];
}

- (School *)getSchool {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  NSDictionary *info = [userDefaults objectForKey:@"school"];
  School *school = [School objectWithKeyValues:info];
  return school;
}

值得注意的是,存入的NSDictionary里面必须不能包含 Null 对象,否则就会抛出异常

将数据储入plist文件中

写入文件方法:writeToFiel:对象调用方法

- (void)writeDataToPlist :(NSString  *)dataKey :(id)data
{
    NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *path=[paths    objectAtIndex:0];
    NSLog(@"path:%@",path);
    NSString *filename=[path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist",dataKey]];
    //写入
    NSFileManager* fm = [NSFileManager defaultManager];
    [fm createFileAtPath:filename contents:nil attributes:nil];
    [data writeToFile:filename atomically:YES];
    if ([fm fileExistsAtPath:filename]) {
        NSLog(@"%@",[NSString stringWithFormat:@"%@文件写入成功",dataKey]);
    }
}
 返回的是文件的路径
- (NSString *)getDataFormPlist :(NSString  *)dataKey
{
    NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *path=[paths objectAtIndex:0];
    NSString *filename=[path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist",dataKey]];
    return filename;
}

读取文件:每个类自带的能够根据文件路径读取文件的方法:[类名 + WithContentOfFiel],如下: WithOfContentFiel 后面跟的是文件的路径

NSString         :[NSString StringWithContentOfFile:]
NSArry           :[NSArry arrayWithContentOfFiel:]
NSDictionary     :[NSDictionary dictionaryWithOfContentFile:]
二进制流          :[NSData dataWithOfContentFiel:]

小结

NSUserDefaults的使用是比较简单的,本文旨在从总体上了解NSUserDefaults的本质和使用方法。

相关文章

网友评论

    本文标题:编码篇-持久化NSUserDefaults

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