zoukankan      html  css  js  c++  java
  • OC的KVC原理

    KVC

    KVC的全称是Key-Value Coding,俗称"键值编码",可以通过一个key来访问某个属性

    常用的API:

    - (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
    - (void)setValue:(id)value forKey:(NSString *)key;
    - (id)valueForKeyPath:(NSString *)keyPath;
    - (id)valueForKey:(NSString *)key;

    setValue:forKey:原理

    编写如下代码验证

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface LBPerson : NSObject
    {
        int _age;
        int _isAge;
        int age;
        int isAge;
    }
    @property (nonatomic, assign) int age;
    
    @end
    
    @implementation LBPerson
    - (void)_setAge:(int)age {
        _age = age;
        NSLog(@"_setAge");
    }
    - (void)setAge:(int)age {
        _age = age;
        NSLog(@"setAge:");
    }
    
    +(BOOL)accessInstanceVariablesDirectly {
        // 是否允许直接访问属性
        return true;
    }
    
    - (void)willChangeValueForKey:(NSString *)key {
        [super willChangeValueForKey:key];
        NSLog(@"willChangeValueForKey");
        
    }
    
    - (void)didChangeValueForKey:(NSString *)key {
        NSLog(@"didChangeValueForKey Start");
        [super didChangeValueForKey:key];
        NSLog(@"didChangeValueForKey End");
    }
    @end
    
    @interface ViewController ()
    @property (nonatomic, strong) LBPerson *person;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        LBPerson *person = [[LBPerson alloc] init];
        self.person = person;
        LBPerson *person1 = [[LBPerson alloc] init];
        [person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:@"test"];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        [self.person setValue:@20 forKey:@"age"];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
    }
    
    - (void)dealloc {
        [self.person removeObserver:self forKeyPath:@"age"];
    }

    从上述代码的打印结果,可以验证setValur:forKey:,会顺序调用setKey、_setKey,如果没找到方法,会调用accessInstanceVariablesDirectly。如果该方法返回的是true,会按照优先级给属性赋值age、isAge、_age、_isAge。如果还没有找到,就会报错。调用结果如下图所示:

    通过打印也验证了,setValue:forKey:也会触发KVO

    valueForKey:原理

    - (int)getAge
    {
        return 1;
    }
    
    - (int)age
    {
        return 2;
    }
    
    - (int)isAge
    {
        return 3;
    }
    
    - (int)_age
    {
        return 4;
    }

    通过打印可验证,valueForKey的调用顺序getAge、age、isAage、_age

  • 相关阅读:
    SQL Server Code tips (持续更新)
    Oracle 函数 “判断数据表中不存在的数据,才允许通过”
    Oracle 函数 “把当前的用户(审核人,审核通过后)插入到数据表中”
    Oracle 函数 “自动生成订单号”
    Oracle中的instr()函数 详解及应用
    Oracle中的substr()函数 详解及应用
    Spring实战(三)Spring中装配Bean的三种方式---XML、JavaConfig、AutoWire
    Spring实战(二)Spring容器和bean的生命周期
    Spring实战(一)Spring简介---呕心沥血只为让Java开发更简单。
    git、git bash、git shell
  • 原文地址:https://www.cnblogs.com/muzichenyu/p/14027981.html
Copyright © 2011-2022 走看看