起底OC之——KVC揹着咱們幹了什麼

三個問題

在文章的最開始,先拋出三個問題:bash

  1. OC是否存在真正意義上的「私有變量」?
  2. 爲何蘋果要提供KVC這門技術?
  3. KVC的完整調用流程是怎麼樣的?

使用KVC訪問「私有變量」

對第一個問題,答案是NO,OC並不存在真正意義上的「私有變量」。咱們來看這樣的一段代碼:ui

//Teacher.h文件
@interface Teacher : NSObject

@end

//Teacher.m文件
@interface Teacher ()
{
    @private NSInteger age;    //age爲Teacher類的私有變量
}
@end

@implementation Teacher
- (instancetype)init{
    if (self = [super init]) {
        age = 10;
    }
    return self;
}
@end
複製代碼

Teacher類中存在一個私有變量age,在Teacher的init方法中設置age=10,照理說這個age外界是沒法訪問的,這一點也符合面嚮對象語言的封裝特性,可是(永遠有個可是,敲黑板了,這裏是重點),使用KVC技術,咱們能夠打破封裝特性,代碼以下:spa

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    Teacher *t = [Teacher new];
    NSLog(@"teacher's age = %@", [t valueForKey:@"age"]);
}
@end
複製代碼

運行程序,而後咱們看一下打印結果:code

結論1:只要咱們知道私有成員變量的名字並結合KVC技術,在OC的世界裏,根本沒有「祕密」😅cdn

爲何蘋果要提供KVC給咱們?

雖然KVC的確把面嚮對象語言撕開了一道口子,可是換個角度想,這道口子同時也給iOS開發者提供了必定的便利性。也就是說,KVC其實是一把雙刃劍,用得好,能夠在特定場景下爲咱們高效解決需求,用得很差,後果一樣可怕。對象

例如,當我嘗試用KVC訪問Teacher類中並不存在的變量「gender」時,程序直接Crash了: blog

咱們分析一下這個Crash,發現是**valueForUndefinedKey:**方法拋出的異常,咱們試着來實現一下這個系統方法,不妨先返回nil,而後再運行一次: 開發

這一次系統沒有Crash,並且gender打印了(null)。從結果上能夠看出,當KVC找不到gender這個值時,會來到valueForUndefinedKey:方法,給咱們最後一次機會,只要咱們返回一個值來回應KVC對gender的訪問,即使是返回nil,系統也不至於Crash。get

結論2:KVC是一把雙刃劍,有利也有弊,經過重寫valueForUndefinedKey:方法,能夠規避使用KVC的弊端string

KVC的調用流程

字不如圖,咱們直接看KVC的調用流程圖:

簡單解釋一下,當咱們調用valueForKey:方法時,KVC爲咱們作了如下幾件事:

  • 第一步,先去尋找「符合條件」的訪問方法,即getter方法,若是存在那就調用,並結束流程;
  • 第二步,若是第一步找不到對應的訪問方法,再調用系統的accessInstanceVariablesDirectly方法,該方法默認返回YES,它本質上是一個開關,用來控制是否要繼續尋找「符合條件」的成員變量。
    • 若是accessInstanceVariablesDirectly返回YES,繼續找「符合條件」的成員變量,找到了就返回其值,並結束流程,找不到就進入第三步;
    • 若是accessInstanceVariablesDirectly返回NO,不須要找成員變量,直接斷定這個key值爲UndefinedKey(未定義的key值,也就是該key不存在),此時流程來到第三步;
  • 第三步,調用valueForUndefinedKey:方法,並拋出Crash異常,結束調用。但若是咱們重寫了valueForUndefinedKey:方法,並返回一個明確的值給UndefinedKey,則不拋出Crash異常。

前面的解釋裏,我屢次用了「符合條件」這個詞,怎麼理解?仍是用圖說話,KVC會按照下圖所示的格式,逐一去尋找對應的方法或者成員變量,感興趣的能夠本身寫個demo試試看。

結論3:KVC的調用流程分三步走,先找方法,再找成員變量,最終還找不到,就直接調用valueForUndefinedKey:來拋出異常。

總結

  • 由於KVC技術的存在,在OC的世界裏沒有真正意義上的「私有變量」;
  • KVC是一把雙刃劍,有利也有弊,但經過重寫valueForUndefinedKey:方法,能夠規避使用KVC的弊端
  • KVC的調用流程分三步走,先找方法,再找成員變量,最終還找不到,就直接調用valueForUndefinedKey:來拋出Crash異常。
相關文章
相關標籤/搜索