对象归档与KVC KVO

Posted 亚洲小炫风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对象归档与KVC KVO相关的知识,希望对你有一定的参考价值。

对象归档是一个过程,即某种格式来保存一个或者多个对象,以便以后还原这些对象
在其他语言中,对象归档也叫对象序列化
对象归档包括两个过程
--将对象状态写入文件
--从文件中写入对象

自定义对象只有实现NSCoding协议(ios 13需要支持NSSecureCoding)才能支持归档操作
-initWithCoder:从文件中还原对象(解档)
-encodeWithCoder: 将对象归档

User.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface User : NSObject<NSSecureCoding>

@property(nonatomic,copy) NSString *name;
@property(nonatomic,assign) int age;
@end

NS_ASSUME_NONNULL_END

User.m

#import "User.h"

@implementation User

//解档
- (instancetype)initWithCoder:(NSCoder *)coder

    self = [super init];
    if (self) 
        self.name =[coder decodeObjectForKey:@"name"];
        self.age = [coder decodeIntForKey:@"age"];
    
    return self;

+ (BOOL)supportsSecureCoding

    return true;


- (void)encodeWithCoder:(NSCoder *)coder

    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeInt:_age forKey:@"age"];


- (NSString *)description

    return [NSString stringWithFormat:@"name:%@ age:%d", _name,_age];


@end

 User *u=[[User alloc] init];
    u.name=@"张三";
    u.age=14;
    
    NSError *error;
    
    NSData *data=[NSKeyedArchiver archivedDataWithRootObject:u requiringSecureCoding:YES error:&error];
    if(error!=nil)
    
        NSLog(@"======>归档错误:%@",error);
        return;
    
    
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"test.archiver"];
    //创建文件
    [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
    //写入
    [data writeToFile:path atomically:YES];
 
    
    
    
  
    //解档
    NSData *data2=[NSData dataWithContentsOfFile:path];
 
    error=nil;
    User *unarchiverUser=(User *)[NSKeyedUnarchiver unarchivedObjectOfClass:[User class] fromData:data2 error:&error];
    if(error!=nil)
    
        NSLog(@"======>解档错误:%@",error);
    
    NSLog(@"=====>unarchiverUser:%@",unarchiverUser);

将多个对象归档在同一个文件中

    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"test22.archiver"];
    
   //将多个对象归档在同一个文件中
    User *user=[[User alloc] init];
    user.name=@"张三";
    user.age=24;
    
    User *user2=[User new];
    user2.name=@"李四";
    user2.age=25;
    

    NSKeyedArchiver *archiver=[[NSKeyedArchiver alloc] initRequiringSecureCoding:NO];
    [archiver encodeObject:user forKey:@"user"];
    [archiver encodeObject:user2 forKey:@"user2"];
    
    [archiver.encodedData writeToFile:path atomically:YES];
    
    [archiver finishEncoding];


    
  

    
    NSData *data=[NSData dataWithContentsOfFile:path];
    NSKeyedUnarchiver *unarchiver=[[NSKeyedUnarchiver alloc] initForReadingFromData:data error:nil];
    [unarchiver setRequiresSecureCoding:NO];
    User *unarchiverUser=[unarchiver decodeObjectForKey:@"user"];
    User *unarchiverUser2=[unarchiver decodeObjectForKey:@"user2"];
    NSLog(@"======>test unarchiverUser:%@",unarchiverUser);
    NSLog(@"======>test unarchiverUser2:%@",unarchiverUser2);


kvc( Key-value coding) 键值对编码 本质对象就是字典 ,类似java的反射

user.h

#import <Foundation/Foundation.h>
#import "Teacher.h"

NS_ASSUME_NONNULL_BEGIN

@interface User : NSObject
@property(nonatomic,copy)  NSString *name;
@property(nonatomic,assign) int age;

@property(nonatomic,strong) Teacher *teacher;
@end

NS_ASSUME_NONNULL_END

    User *u=[[User alloc] init];
    u.name=@"李四";
    [u setValue:@"张三" forKey:@"name"];
    NSLog(@"=======>u:%@",u);//=======>u:<User: 0x600003ace8e0>
    
    Teacher *t=[Teacher new];
    t.name=@"李明老师";
    [u setValue:t forKey:@"teacher"];
    NSLog(@"=======>u.teacher:%@",u.teacher.name);//=======>u.teacher:李明老师
    
    //forpath 可以指定嵌套的属性的值
    [u setValue:@"张明老师" forKeyPath:@"teacher.name"];
    NSLog(@"=======>u.teacher:%@",u.teacher.name);//=======>u.teacher:张明老师
    
    
    NSString *name=   [u valueForKey:@"name"];
    NSLog(@"=======>name:%@",name);// =======>name:张三
    NSString *teacherName=[u valueForKeyPath:@"teacher.name"];
    NSLog(@"=======>teacherName:%@",teacherName);// =======>u.teacher:张明老师

kvo 是 key value obsever 监视对象改变

实例:

User.h

#import <Foundation/Foundation.h>
#import "Watcher.h"
NS_ASSUME_NONNULL_BEGIN

@interface User : NSObject
@property(nonatomic,strong) NSString *name;
@property(nonatomic,strong) Watcher *watcher;
@end

NS_ASSUME_NONNULL_END

User.m

#import "User.h"

@implementation User

- (void)setWatcher:(Watcher *)watcher
    _watcher=watcher;
    [self addObserver:self.watcher forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:@"address changed"];



- (void)dealloc

    //销毁的时候移除观察者
    if(_watcher!=nil)
        [self removeObserver:self.watcher forKeyPath:@"name"];
    

@end

Watcher.h


#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Watcher : NSObject

@end

NS_ASSUME_NONNULL_END

Watcher.m

#import "Watcher.h"

@implementation Watcher

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context

    NSLog(@"========>数据发生改变了 keyPath:%@",keyPath);//========>数据发生改变了 keyPath:name
    NSLog(@"========>数据发生改变了 change old:%@",change[@"old"]);//========>数据发生改变了 change old:张三
    NSLog(@"========>数据发生改变了 change new:%@",change[@"new"]);//========>数据发生改变了 change new:李四
    
    NSLog(@"========>数据发生改变了 change new valueForKeyPath:%@",[object valueForKeyPath:keyPath]);//========>数据发生改变了 change new valueForKeyPath:李四
    NSLog(@"========>数据发生改变了 change context:%@",context);//========>数据发生改变了 change context:address changed

@end

总结:1.观察一个对象 有观察者Watcher 被观察者User
2.被观察者属性改变可以通过注册一个对象 到具体的属性上
2. 观察者遇到被观察者发生改变 观察者会回调 observeValueForKeyPath 系统方法

以上是关于对象归档与KVC KVO的主要内容,如果未能解决你的问题,请参考以下文章

对象归档与KVC KVO

对象归档与KVC KVO

iOSKVC 与 KVO

KVC 与 KVO 理解

KVC 与 KVO

KVC与KVO