美文网首页iOS面试题相关知识点
iOS开发中数据持久化(二):NSUserDefaults实现存

iOS开发中数据持久化(二):NSUserDefaults实现存

作者: 落叶兮兮 | 来源:发表于2021-01-06 16:16 被阅读0次

    这篇文章主要讲述NSUserDefaults的简单使用
    Demo地址
    对应实现的文件是NSUserDefaultViewController.m文件和person.m文件
    存储数据成功后,在沙盒中查看相应的存储文件数据如下图所示:

    NSUserDefault存储数据

    注意,NSUserDefaults除了存储一些基本的数据类型之外,还可以存储NSArray、NSDictionary等一些基本的数据类型,如果想要存储自定的数据类型,执行将自定义对象转化为NSData,然后使用NSUserDefaults存储,上图中Person就是自定义对象,注意,每次读取获得的数据类型都是不可变类型,例如,你存储进去的是NSMutableArray类型,但是读取出来之后就是NSArray类型

    如何查看app的沙盒文件

    模拟机

    在这里,先说一下,如何查看文件存储的沙盒位置
    如果是使用xcode提供的模拟机,那么文件就在自己电脑上,使用

    //获取沙盒根目录
    NSString *directory = NSHomeDirectory();
    NSLog(@"directory:%@", directory);
    

    这样可以获得app沙盒文件的根目录

    真机

    如果使用的是真机测试
    在xcode中,点击windows->Devices And Simulators,找到我们对应的app名称


    image.png

    选中,点击下方的齿轮


    image.png

    点击Download Container即可将app的沙盒文件下载到电脑上,然后可以查看

    NSUserDefaults实现

    首先定义两个按钮,一个用于写入数据,一个用于读取数据
    在NSUserDefaultViewController.h文件中

    @property (nonatomic, strong) UIButton *NSUserDefaultWriteButton;
    @property (nonatomic, strong) UIButton *NSUserDefaultReadButton;
    

    之后,在.m中实现相应的懒加载和布局

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        self.title = @"NSUserDefault存储";
        self.navigationController.navigationBar.translucent = NO;
        self.view.backgroundColor = [UIColor whiteColor];
        
        [self.view addSubview:self.NSUserDefaultWriteButton];
        [self.NSUserDefaultWriteButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(self.view);
            make.centerY.equalTo(self.view);
            make.width.greaterThanOrEqualTo(@0);
            make.height.equalTo(@30);
        }];
        [self.view addSubview:self.NSUserDefaultReadButton];
        [self.NSUserDefaultReadButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(self.view);
            make.top.equalTo(self.NSUserDefaultWriteButton.mas_bottom).offset(20);
            make.width.greaterThanOrEqualTo(@0);
            make.height.equalTo(@30);
        }];
    }
    
    - (UIButton *)NSUserDefaultWriteButton {
        if (_NSUserDefaultWriteButton) {
            return _NSUserDefaultWriteButton;
        }
        _NSUserDefaultWriteButton = [[UIButton alloc] initWithFrame:CGRectZero];
        _NSUserDefaultWriteButton.titleLabel.font = [UIFont systemFontOfSize:18];
        [_NSUserDefaultWriteButton setTitle:@"NSUserDefault写入数据" forState:UIControlStateNormal];
        [_NSUserDefaultWriteButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [_NSUserDefaultWriteButton addTarget:self action:@selector(nsUserDefaultWirteData) forControlEvents:UIControlEventTouchUpInside];
        return _NSUserDefaultWriteButton;
    }
    
    
    - (UIButton *)NSUserDefaultReadButton {
        if (_NSUserDefaultReadButton) {
            return _NSUserDefaultReadButton;
        }
        _NSUserDefaultReadButton = [[UIButton alloc] initWithFrame:CGRectZero];
        _NSUserDefaultReadButton.titleLabel.font = [UIFont systemFontOfSize:18];
        [_NSUserDefaultReadButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [_NSUserDefaultReadButton setTitle:@"NSUserDefault读出数据" forState:UIControlStateNormal];
        [_NSUserDefaultReadButton addTarget:self action:@selector(nsUserDefaultReadData) forControlEvents:UIControlEventTouchUpInside];
        return _NSUserDefaultReadButton;
    }
    
    - (void)nsUserDefaultWirteData {
       NSLog(@"NSUserDefault写入数据");
    }
    
    - (void)nsUserDefaultReadData {
       NSLog(@"NSUserDefault读出数据");
    }
    
    

    之后,我们就可以在按钮对应的点击方法中实现存储数据和读取数据

    接下来一个一个说
    先获取到唯一的NSUserDefaults对象

    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    

    存储的代码写在nsUserDefaultWirteData方法中,读取的代码写在nsUserDefaultReadData中

    1.整数

    //存储整数
       [ud setInteger:111 forKey:@"INT"];
    
     //读取NSInteger
        NSInteger i = [[ud objectForKey:@"INT"] integerValue];
        NSLog(@"i = %ld",(long)i);
    

    2.BOOL值

     //存储bool值
        [ud setBool:YES forKey:@"BOOL"];
    
    //读取bool值
        BOOL isYES = [ud objectForKey:@"BOOL"];
        NSLog(@"isYES = %d",isYES);
    

    3.浮点数

    //存储浮点数
        [ud setFloat:1.8 forKey:@"float"];
    
    //读取浮点数
        CGFloat f = [[ud objectForKey:@"float"] floatValue];
        NSLog(@"f = %f",f);
    

    4.NSString字符串

    //存储字符串NSString
        [ud setObject:@"落叶兮兮" forKey:@"Name"];
    
    //读取NSString
        NSString *name = [ud objectForKey:@"Name"];
        NSLog(@"name = %@",name);
    

    5.NSNumber

    //存储NSNumber
        NSNumber *num = [NSNumber numberWithInteger:100];
        [ud setObject:num forKey:@"NUM"];
    
    //读取NSNumber
        NSNumber *number = [ud objectForKey:@"NUM"];
        NSLog(@"number = %@",number);
    

    6.数组NSArray

    //存储数组
        NSArray *array = [NSArray arrayWithObjects:@"11",@"22",@"33",nil];
        [ud setObject:array forKey:@"ARRAY"];
    
    //读取NSArray
        NSArray *arr = [ud objectForKey:@"ARRAY"];
        NSLog(@"arr = %@",arr);
    

    7.字典NSDictionary

       NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setValue:@"落叶兮兮" forKey:@"Id1"];
        [dic setValue:@"雪花飞舞" forKey:@"Id2"];
        [ud setObject:dic forKey:@"Dictionary"];
    
    //读取NSDictionary
        NSDictionary *dic = [ud objectForKey:@"Dictionary"];
        NSLog(@"dic id1 = %@",[dic objectForKey:@"Id1"]);
        NSLog(@"dic id2 = %@",[dic objectForKey:@"Id2"]);
    

    注意,NSUserDefaults读取后的类型都是不可变的类型

    还有其他的一些基本数据类型,比如NSDate,Double等,这里就不再写了,下面主要讲自定义对象的存储,这部分比较复杂

    自定义对象Person

    对于NSUserDefault存储自定义对象,相比其他类型,这部分是最复杂的,将这部分放在最后再写

    我们都知道,存储自定义对象,应该将对象转换为NSData数据类型,然后将其存储到plist文件中,这里转换需要用到NSKeyedArchiver归档和NSKeyedUnarchiver解档

    首先,我们新建一个文件,命名为Person
    定义基本的属性和赋值方法
    在person.h文件中,

    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    
    - (void)setName:(NSString *)name age:(NSInteger)age;
    

    在person.m文件中,

    - (void)setName:(NSString *)name age:(NSInteger)age {
        self.name = name;
        self.age = age;
    }
    

    这样基本类Person就定义好了,在NSUserDefaultViewController中初始化并赋值
    在nsUserDefaultWriteData方法中

    Person *person = [[Person alloc] init];
    [person setName:@"落叶兮兮" age:24];
    

    之后,将Person转化为NSData对象

    //使用error接收错误信息,一旦出错,error里面存储的就是错误信息
    NSError *error = nil;
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:&error];
    if (error) {
            NSLog(@"写入数据时转换失败,失败的原因是%@",error);
        }
    

    运行之后,报错


    自定义对象转化为NSData对象报错

    原因是Person类没有实现NSSecureCoding协议,关于这个协议方法,主要是为了数据安全,防止被别人篡改,具体的可以去苹果官方文档查看

    接下来就很简单了,我们需要实现相应的协议方法
    person类遵守<NSSecureCoding>

    @interface Person : NSObject<NSSecureCoding>
    

    点进去可以看到NSSecureCoding协议遵守<NSCoding>协议


    NSSecureCoding协议

    所以需要实现NSCoding协议的方法
    在Person.m文件中

    //1.编码方法
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        [aCoder encodeObject:self.name forKey:@"PersonName"];
        [aCoder encodeInteger:self.age forKey:@"PersonAge"];
    }
    
    //2.解码方法
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self = [super init];
        if (self) {
            self.name = [aDecoder decodeObjectForKey:@"PersonName"];
            self.age = [aDecoder decodeIntegerForKey:@"PersonAge"];
        }
        return self;
    }
    

    注意,根据NSSecureCoding协议的介绍,我们必须实现supportsSecureCoding方法,并且返回YES,这样才是支持NSSecureCoding协议

    而且必须得是类方法,刚开始我写成了实例方法,结果一直报错,转化失败

    + (BOOL)supportsSecureCoding {
        NSLog(@"执行了这个方法");
        return YES;
    }
    

    此事执行转化方法,发现没有错误出现,接下来是读取,读取获得的是NSData对象,需要将其转化为Person自定义对象,使用解档

    NSData *data = [ud objectForKey:@"Person"];
        Person *person = [[Person alloc] init];
        NSError *error = nil;
        person = [NSKeyedUnarchiver unarchivedObjectOfClass:[Person class] fromData:data error:&error];
        if (error) {
            NSLog(@"转化出错,出错的原因为%@",error);
        }
        NSLog(@"person name = %@",person.name);
        NSLog(@"person age = %ld",(long)person.age);
    

    运行之后发现能够正常输出内容,转化类型无错误发生

    9.存储路径

    //NSUserDefault写入数据,默认放在library/Preferences文件夹下,以.plist文件存放
        
       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
        NSString *path = [paths objectAtIndex:0];
        NSLog(@"数据持久化的路径为:%@",path);
    

    最好使用模拟机运行,模拟机运行之后获得path,直接在finder中command+G可以直接到存储的plist文件

    如果使用真机,需要将数据包下载到电脑上才能看到,比较麻烦

    总结

    最终的数据存储图为:


    NSUserDefault存储数据

    Demo地址
    对应实现的文件是NSUserDefaultViewController.m文件和person.m文件

    总结

    iOS开发中数据持久化总结(一)
    iOS开发中数据持久化总结(二):NSUserDefault实现数据存储
    ios开发中数据持久化总结(三):NSKeyArchive归档解档的实现
    ios开发中数据持久化总结(四):使用FMDataBase存储数据

    相关文章

      网友评论

        本文标题:iOS开发中数据持久化(二):NSUserDefaults实现存

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