Objective-C KVC講解,包你看懂會用

KVC:Key Value Coding,取其三個單詞首字母濃縮而成。直白翻譯過來就是鍵值編碼,什麼意思呢?簡單來講,就是操做一個對象,也能夠像操做字典同樣,經過key來取值和賦值。
網絡

咱們先建立一個HMPerson類來試驗一下。框架

 

而後實例化HMPerson類的對象,此時,咱們若是想要給它的name和age兩個屬性賦值和取值,就能夠用點語法來操做,如圖:編碼

    • 可是,這種點語法方式顯得着實太low,接下來咱們就用比較高大上的方式——KVC的方式來賦值和取值。
      咱們先簡單看看KVC裏的幾個方法:
      賦值:翻譯

    • 解釋:第一個參數傳入想賦的值,第二個參數傳入想接收值的屬性
    • - (void)setValue:(nullable id)value forKey:(NSString *)key;
      - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
      

      解釋:這種方式比較暴力,後頭會解釋3d

    • -(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id>*)keyedValues;
      

      取值:對象

    • - (nullableid)valueForKey:(NSString *)key;
      - (nullable id)valueForKeyPath:(NSString *)keyPath;
      
    • 解釋:參數是傳入你想取值的屬性名 咱們都知道,OC中任何對象都直接或間接的繼承自NSObject,而在Foundation框架中,NSObject有個叫「NSKeyValueCoding」的分類,裏面就包含了上面全部這些KVC方法。所以任何對象均可以經過KVC來取值和賦值,也就是說即便咱們剛剛本身建立的Person類也有這些方法。 取值和賦值具體在代碼中的應用以下:
    • 咱們發現KVC的方式使用起來也沒任何問題。可是,不少同窗會疑惑,爲何
      16要加個「@」符號呢?還有取值時爲何還要調用一下intValue方法呢?不這麼寫可不能夠?答案是不行的,咱們先看若是不這麼寫會怎樣
    • 緣由以下 
      1. KVC中,賦值時傳入的值都只能是對象類型,沒法直接傳入基本數據類型,所以,在給age屬性賦值時,用了一個@符號,把16這個數字快速包裝成了NSNumber類型(@加數字是快速建立NSNumber的語法) 
      2. 經過KVC取值時,全部的返回值類型都是id類型(也即對象類型),所以沒法直接用基本數據類型的變量來接收,必須調用其對應的類型轉換代碼先進行類型轉換另外須要注意:KVC中全部的屬性名都要以字符串的形式傳入此時有同窗會疑問了:「我勒個去!用
        KVC這麼麻煩,還不如直接用點語法方便多了」,對,通常狀況下是這樣!可是,用
        KVC的方式有你意想不到優勢!
    • KVC
      **的優勢合集blog

      優勢一:破門而入:與別人家的「私人專屬」親密接觸**
      咱們都知道,若是@property寫在.h文件中,表明外界能夠經過調用對應的setter和getter方法(或點語法)來訪問對應的私有成員變量,但若是寫在.m中,表明只容許本類中訪問,其餘地方訪問不了。所以,咱們給以前的Person類在.m文件中寫一個延展,把.h文件的@property挪到.m的延展中。而且在.m文件中再加一個用@private修飾的成員變量
      如圖:繼承

    • 此時,咱們經過點語法來給屬性賦值取值即會報錯,如圖
    • 可是,若是是KVC方式,此時依然堅挺!
    • 到此爲止,KVC的好處之一獲得完美體現:不管類中的成員是否私有,用KVC均可以強行「破門而入」,對它們正常取值和賦值。
      除此之外,還有個顯而易見的好處是:KVC中無論你的成員變量是否加下劃線,你用KVC取值和賦值時傳入的屬性名均可以不帶下劃線。
      優勢二:大大簡化字典轉模型代碼 
      不少時候,咱們經過加載本地文件,或者網絡請求會獲得一個數據字典,爲了方便調用,通常咱們都會將這個字典轉換爲對應的模型類,可是,不用KVC的轉換方法太過費勁,如圖:
      先有一個HMPerson類
    • 而後有一個字典,而且把字典裏的元素賦值給HMPerson對象,以下圖所示:
    • 所以,咱們能夠將KVC實現字典轉模型的方法直接用這個循環解決
    • KVC提供了一套更簡潔的操做方式,只需你傳入一個字典,就能夠幫你自動把字典裏的每一項賦值給你實體類對應的屬性,如圖:
    • 對,僅需調用setValuesForKeysWithDictionary方法,傳入字典便可。這個方法內部,幫咱們作了咱們剛剛循環字典的操做,所以僅僅這一個方法就可完成字典數據轉模型數據,今後,媽媽不再用擔憂我寫多餘代碼了!字符串

      注意:用setValuesForKeysWithDictionary或者本身寫循環作字典數據轉模型數據時,必須保證明體類的屬性跟字典中的key名字一一對應,而且屬性能夠比字典多,可是絕對不能比字典的元素少!

    • KVC
      **疑問解密get

      疑問解密
      1:
      **

      使用KVC是直接對成員變量賦值,仍是調用了這個成員變量對應的setter和getter方法呢?
      爲了解決這個疑問,咱們給HMPerson類里加一個私有的成員變量name,而且給它寫好對應的getter和setter方法,如圖:

      • 而後用KVC的方式給name賦值和取值,如圖:
      • 經過觀察,咱們發現用KVC來賦值時,對應的setter方法能被調用,用KVC來取值時,對應的getter方法也能被調用。
        所以小夥伴們不用擔憂KVC會破壞本身已經寫好的屬性封裝規則。
        疑問解密1小分支:

        若是沒有getter方法和setter方法時,KVC是怎麼找成員變量的呢?
        爲了弄清這個問題,咱們刪掉name的getter和setter方法。而後經過KVC方式賦值取值,會發現,依然能夠賦值和取值成功。而且是給p對象的成員變量_name賦值的。如圖:

      • 小夥伴們可能好奇的是,傳入的Key是「name」,而賦值成功的是「_name」成員變量,那麼若是,我同時有兩個成員變量,一個叫「_name」,一個叫「name」,那KVC是給誰賦值的呢?
        爲了搞清這個問題,咱們先改良一下HMPerson類。
        • 而後,咱們再次用KVC來調用,而且下一個斷點看看,到底是給哪一個成員變量賦值的。如圖:
        • 經過結果,咱們發現,依然是對「_name」這個成員變量賦值的。這時候咱們是否能夠說,KVC永遠是對帶下劃線的成員變量賦值的呢?那倒也未必,咱們來繼續看,假如此時給HMPerson刪掉「_name」,只留「name」,又會是怎樣。
        • 此時發現,用KVC賦值的就是這個不帶下劃線的成員變量(即name)了。
          所以,咱們能夠總結出,KVC賦值和取值的一套順序:

          1. 用KVC取值或賦值時,會優先找這個屬性對應的getter或setter方法來對這個屬性賦值
          2. 若是找不到,則會查找帶下劃線的屬性,若是找到則賦值
          3. 若是依然找不到,則會查找不帶下劃線的屬性,若是找到則賦值
          4. 若是仍是找不到,則報錯(可讓它不報錯,後文會詳述)
            **疑問解密2:複合路徑

          **
          setValue:屬性值 forKeyPath:屬性路徑 valueForKeyPath:屬性名

          複製代碼

          後面帶Path的跟以前咱們用的KVC有什麼不一樣呢?咱們來研究研究!
          假設此時有一個Dog類,而Person類裏也有個屬性是Dog類型的,叫pet,如圖

        • 若是此時實例化Person對象,要用KVC操做pet屬性裏的nickName屬性就不太方便,只能先取出pet屬性指向的Dog對象,再來操做nickName屬性,以下:
        • 而帶Path的方法,就是用來簡化這種操做的,咱們看
        • 所以,也就是說,若是須要操做訪問一些「屬性裏的屬性」時,就用帶Path的方法來操做。
          ** 疑問解密
          3:

          **
          若是用
          KVC賦值時,某一個
          Key,類中沒有會怎樣?

          例如:咱們的
          HMPerson類如今沒有
          salary屬性。

        • 此時,經過
          KVC的方式賦值,運行時會崩潰
        • 所以,用KVC時傳入的Key必須保證類中存在同名的屬性。不然會運行時崩潰。那麼若是我不但願運行時直接崩潰,而是來一個相對友好的提示,不要讓它崩潰,該怎麼辦呢?
          咱們就須要在HMPerson類裏重寫setValue:值 forUndefinedKey:鍵方法,這樣,當用KVC對Person對象賦值了一個Key與屬性對應不上的錯誤時,系統會自動調用這個方法,咱們來試試看!
          如圖:
        • 此時,不管你輸錯多少次HMPerson對象不存在的屬性時,都不會在運行時讓程序崩潰,達到報錯「友好」的目的。
          **總結

          **
          KVC是一套方便咱們用字符串來操做對象的機制,可使得操做對象時跟操做字典同樣的靈活。在字典轉模型的領域中應用起來極爲方便,而且
          KVC能夠輕鬆的幫咱們突破訪問限制的一些問題,直接訪問到私有成員。

        • KVC也有其缺點:例如在編碼時很容易輸錯key致使問題,語法相較點語法而言也略微繁瑣。但萬事萬物不也正如KVC通常既有其優勢,也存在其不足之處,不是嗎?
相關文章
相關標籤/搜索