KVC講解

今天趁着項目bug修復完了,來說解一下OC知識的另外一個技術點-KVC!針對KVC,講解兩個知識點atom

  • 經過KVC修改屬性會觸發KVO麼?
  • KVC的賦值過程是怎樣的?原理是什麼?
  • KVC的取值過程是怎樣的?原理是什麼?

 

1、問:經過KVC修改屬性會觸發KVO麼?spa

答:會觸發KVO3d

建立工程項目TestKVO,ZXYPerson類有一個屬性age,在控制器ViewController中添加屬性觀察者KVO,項目代碼以下code

@interface ViewController ()
@property(nonatomic,strong) ZXYPerson
*p; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _p = [[ZXYPerson alloc]init]; _p.age = 10; [_p addObserver:self forKeyPath:@"age" options: NSKeyValueObservingOptionNew context:nil]; [_p setValue:@12 forKeyPath: @"age"]; } -(void)dealloc { [_p removeObserver:self forKeyPath:@"age"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ NSLog(@"*********%@", change); }

上面橙色文字經過KVC方式更改屬性的值,將上面代碼運行結果以下:server

 

經過上面發現setValue:forKeyPath觸發了KVO,同理發現setValue:forKey也會觸發KVO,可是這兩個方法有什麼區別呢?blog

setValue:forKeyPath會一層一層的(沿着路徑)向下找,然而setValue:forKey並不會這樣!(假如ZXYPerson養了一隻貓,貓有age屬性 ,經過"_p.cat.age"設置應該用setValue:forKeyPath,不能用setValue:forKeyrem

思考: 爲何KVC更改屬性值會觸發KVO?那就須要講解下面知識。get

 

2、問:KVC的賦值過程是怎樣的?原理是什麼?博客

 setValue:forKey:的原理it

accessInstanceVariablesDirectly方法的默認返回值是YES

下面一一驗證上面的順序:

 驗證setValue:forkey調用過程不須要用到KVO,去除多餘的代碼以後,簡化成以下:

#import "ViewController.h"
#import "ZXYPerson.h"

@interface ViewController ()

@property(nonatomic,strong) ZXYPerson *p;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    _p = [[ZXYPerson alloc]init];
    [_p setValue:@12 forKeyPath: @"age"];
    
}

@end


#import "ZXYPerson.h"

@implementation ZXYPerson

- (void) setAge:(int)age {
    NSLog(@"調用了setAge方法");
}

- (void) _setAge: (int)age {
    NSLog(@"調用了_setAge方法");
}

@end

去除了age屬性的聲明,看看KVC賦值的前期過程(按照setKey, _setKey方法走)

 同時寫了兩個方法,優先調用setAge方法,假如將setAge方法註釋掉

 註釋掉setAge方法後,久調用了_setAge方法,證明了KVC的前期賦值狀況!

 

若是兩個方法都沒有實現,此時KVC會accessInstanceVariablesDirectly方法,返回Yes表明能夠直接訪問成員變量,反之不能訪問成員變量!

若是返回爲Yes,會按照_key、_isKey、key、isKey成員屬性進行賦值

此時像上面的代碼加入這四個成員變量,以下(前提accessInstanceVariablesDirectly方法返回Yes)

@interface ZXYPerson : NSObject
{
    @public
    int _age;
    int _isAge;
    int age;
    int isAge;
}

@end

加入上述代碼,運行

 首先給_age賦值,當四個成員變量同時出現,假如將int _age成員變量註釋掉,以下:

發現當_age註釋掉以後,優先給_isAge賦值,優先級僅次於_age,假如將_isAge註釋掉以後

 發現給age賦值,同理將age成員變量註釋掉以後

 最後給isAge賦值,符合了上述setValue:forkey的訪問屬性的優先級 _key > _isKey > key > isKey的順序

 

若是這四個成員變量都沒有了,就會報異常

 經過上面講述知道setValue:forKey會觸發KVO

[_p setValue:@12 forKeyPath: @"age"]內部調用至關於

[p willChangeValueForKey @"age"]

p->_age = 12;

[p didChangeValueForKey @"age"]

因此會觸發KVO

以上就是setValue:forKey的賦值全部過程,但願你們再看看上述圖,下面講述KVC如何取值?

 

3、問: KVC的取值過程是怎樣的?原理是什麼?

valueForKey:的原理

 

 下面一一驗證上面的順序:

@interface ZXYPerson : NSObject{
    @public
    int _age;
}

@implementation ZXYPerson

- (int)getAge {
    return 11;
}

- (int)age {
    return 12;
}

- (int)isAge {
    return 13;
}

- (int)_age {
    return 14;
}

@end


@interface ViewController ()
@property(nonatomic,strong) ZXYPerson *p;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    _p = [[ZXYPerson alloc]init];
    _p->_age = 10;
    
    NSLog(@"******%@",[_p valueForKey:@"age"]);
    
}

@end

看看KVC取值的前期過程(按照getAge > age > isAge > _age 方法走)

 

當有四個方法時,會優先調用getAge方法,如上面同樣打印出11,調用了getAge方法!假如把getAge()方法註釋掉,運行代碼:

 

 將getAge()方法註釋掉後,調用了age方法,驗證了getAge > age !假如把age方法註釋掉

 

將getAge()和age()方法註釋掉後,調用了isAge()方法,驗證了getAge > age > isAge !假如把isAge()方法註釋掉 

 

將getAge()和age()方法以及isAge()註釋掉後,調用了_age()方法,驗證了getAge > age > isAge > _age! 

若是四個方法都沒有實現,此時KVC會看accessInstanceVariablesDirectly方法,返回Yes表明能夠直接查找成員變量,反之不能查找成員變量!

若是返回爲Yes,會按照_key、_isKey、key、isKey成員屬性順序查找成員變量

此時像上面的代碼加入這四個成員變量,以下(前提accessInstanceVariablesDirectly方法返回Yes,去除四個方法)

    @public
    int _age;
    int _isAge;
    int age;
    int isAge;

加入了四個成員變量,控制器ViewController加入設置屬性的四個值的

    _p->_age = 11;
    _p->_isAge = 12;
    _p->age = 13;
    _p->isAge = 14;

觀察成員變量的查找順序!驗證_key、_isKey、key、isKey

 

 ZXYPerson有四個成員變量,當向着上面代碼書寫,運行代碼結論是11,對應着_age這個成員變量,因此優先取值_age!當將 _age成員變量註釋掉以及賦值註釋掉後

 

發現運行結果爲12,對應的結果時_isAge, 得出結論 _age > _isAge! 繼續將_isAge成員變量註釋掉以及賦值_isAge以下:

 

 發現運行結果爲13,對應的結果時age, 得出結論 _age > _isAge > age! 繼續將age成員變量註釋掉以及賦值age以下:

 

 發現運行結果爲14,對應的結果時isAge, 得出結論 _age > _isAge > age > isAge! 繼續將isAge成員變量註釋掉以及賦值isAge以下:

 若是都註釋掉,會報異常valueForUndefinedKey錯誤!

以上就是valueForKey的取值全部過程,但願你們再看看上述圖回顧KVC如何取值!

 

上述就是KVC的基本內容,但願對你們有所幫助,能夠關注博客會實時更新,謝謝!!!

相關文章
相關標籤/搜索