2-4 iOS KVC&KVO

KVC

概念:KVC,键-值编码,可以使用字符串直接访问对象的属性,而不需要显式调用存取方法。在运行时动态访问和修改属性的值,而不是在编译时确定。OC所有继承NSObject的类型都能使用KVC。

怎么用?什么时候用?

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值
+ (BOOL)accessInstanceVariablesDirectly;
//默认返回YES,表示如果没有找到Set方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回
- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//和上一个方法一样,只不过是设值。
- (void)setNilValueForKey:(NSString *)key;
//如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
//输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。


使用方法:

Dog* dog = [Dog new];
dog.name = @"KeLe";
[people setValue:dog forKey:@"myDog"];//myDog为People类的属性 @property (nonatomic, strong) Dog *myDog;
NSString* name1 = people.myDog.name;
NSString * name2 = [people valueForKeyPath:@"myDog.name"];//people类的myDog成员也属于自定义类。要获取到myDog中的name属性。1.可以先valueForKey获取到myDog,再通过valueForKey获取到name。但是这样太麻烦了。我们直接用keyPath直接获取成员变量(自定义类)的属性。
NSLog(@"name1:%@   name2:%@",name1,name2);
//打印结果
2018-03-30 11:20:10.129 KVCDemo[1346:95910] name1:KeLe   name2:KeLe

什么时候用?

1.需要获取类的私有属性。比如如何修改textField的placeholder的颜色和字体大小呢?MyTextField setValue: forKeyPath:(_placeHolderLabel.textColor _placeHolderLabel.font)。如果你问我为什么知道UITextField的占位Label的名字是_placeHoldLabel。教你一招:

- (NSMutableArray *)getAllIvarListInClass:(Class)iVarClass {
    unsigned int numIvars; //成员变量个数
    NSMutableArray *allIvar = [NSMutableArray array];
    Ivar *vars = class_copyIvarList(iVarClass, &numIvars);
    NSString *key=nil;
    for(int i = 0; i < numIvars; i++) {
        Ivar thisIvar = vars[i];
        key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];  //获取成员变量的名字
        NSLog(@"variable name :%@", key);
        [allIvar addObject:key];
        key = [NSString stringWithUTF8String:ivar_getTypeEncoding(thisIvar)]; //获取成员变量的数据类型
        NSLog(@"variable type :%@", key);
    }
    free(vars);
    return allIvar;
}
返回当前类的所有成员变量。之后 我们可以通过变量名判断是哪个属性类型。

2.动态取值,设置。如上代码所示。

3.操作集合,NSArray,NSSet。

4.将字典转化为model

    NSDictionary *dict = @{
                           @"name"  : @"zhangsan",
                           @"height" : @"175",
                           };
    // 创建模型
    Person *p = [[Person alloc] init];
    // 字典转模型
    [p setValuesForKeysWithDictionary:dict];
    NSLog(@"person's name is the %@",p.name);

比较常用的场景大概就是这些


KVO

概念:KVO,键-值观察者。即对某个对象的属性添加观察者,当这个属性的值发生变化时,就会调用“observeValueForKeyPath”,我们可以在这个方法里面来进行操作。

      当某个类的对象第一次被添加观察者时。系统在运行时创建该类的派生类,重写了该对象的setter方法,以便添加观察,并将原来类的isa指向派生类。所以当setter这个对象时,调用的是派生类中重写的这套,激活键值观察。

怎么用?什么时候用?

name为myKVC类中的属性。

[myKVC addObserver:self forKeyPath:@"name" options: NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];

当name的值发生变化时:

    

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    //拿到新值/旧值,进行操作
    NSLog(@"newValue----%@",change[@"new"]);
    NSLog(@"oldValue----%@",change[@"old"]);

}

取消监听:

-(void)dealloc
{
    [myKVC removeObserver:self forKeyPath:@"name"];
}

什么时候用呢?

1.监听模型属性,更新UI,比如列表有个阅读数,点击进入详情,阅读数应该+1,返回列表则应该通过对应的UI表现出来。

2.监听上拉刷新,下拉加载的contentoffesize。

3.室内地图,蓝牙开发中,监听当前点的postion。实时更新UI。

4.webview混排监听contentsize。




你可能感兴趣的:(IOS-开发)