字典轉模型

来源:http://www.cnblogs.com/xuan-yuan/archive/2016/04/24/5427832.html
-Advertisement-
Play Games

字典轉模型 1> 什麼是字典轉模型? 字典數據/數組(可以是 plist 文件中的數據也可以是網路後臺的數據等)轉化為模型對象/數組. 2> 註意 模型要提供可以傳入字典參數的構造方法.(一個對象方法和一個類方法) - (instancetype)initWithDict:(NSDictionary ...


字典轉模型

1>   什麼是字典轉模型?

字典數據/數組(可以是 plist 文件中的數據也可以是網路後臺的數據等)轉化為模型對象/數組.

2>   註意

模型要提供可以傳入字典參數的構造方法.(一個對象方法和一個類方法)

- (instancetype)initWithDict:(NSDictionary *)dict;

+ (instancetype)xxxWithDict:(NSDictionary *)dict;

3>   提示:在模型中儘量的使用只讀屬性可以進一步降低代碼的耦合性

4>   優點:

  • 將字典中的數據封裝到一個模型類中,有 MVC 框架思想的優點,可以降低耦合性
  • 所有的字典轉模型可以寫在一處,便於管理,同時也可以降低代碼的出錯率
  • 字典轉模型後,直接把字典中(後臺)的數據轉移到模型的屬性中,外界可以通過直接調用模型的屬性來獲取數據,從而可以提高代碼的編碼效率
  • 由於模型是一個單獨的類中進行的,外界不用關心類中的細節,只要使用就可以,更好的體現了面向對象的思想.

5>   使用步驟(簡單舉例)

  • 在模型的.h 文件中聲明所需要的所有屬性
  • 在模型的.h實例化兩個方法

- (instancetype)initWithDict:(NSDictionary *)dict;

+ (instancetype)appInfoWithDict:(NSDictionary *)dict;

  • 在模型的.m 文件中,通過實現兩個方法獲取數據

- (instancetype)initWithDict:(NSDictionary *)dict{

    self = [super init];

     if (self) {//給聲明的屬性賦值

         self.name = dict[@"name"];

         self.icon = dict[@"icon"];

     }

     return self;

 }

 

 + (instancetype)appInfoWithDict:(NSDictionary *)dict{

     return [[self alloc] initWithDict:dict];

 }

  • 聲明空控制項的屬性,併在懶載入中直接實例化賦值
  • 在 VC 的. m 文件中聲明一個目標控制項的屬性
  • 懶載入控制項:在懶載入的判斷為空的時候,通過 bundle à path à 通過 path 路徑把數據轉到模型(數組)中 à 創建一個臨時可變數組(用於盛放數據) à 遍歷通過路徑獲取的數據 à 給臨時數組賦值 à 將臨時數組賦值給模型對象

6 KVC 下的字典轉模型

            > 什麼是 KVC?

 KVC --  key  value  coding鍵值編碼   (註:KVO key value observe   鍵值觀察  監聽某個模型對象的屬性,當屬性改變時會及時通知你)

> KVC 是作用?

            KVC 可以理解為cocoa 的大招,是指在程式運行過程中,可以動態的給屬性進行賦值,包括只讀屬性和私有屬性.(可以理解為,只要對象有屬性,就能給屬性賦值)

> KVC 的使用機理

                        > 使用 KVC 修改對象的屬性時, KVC 會自動判斷對象的屬性,並完成類型轉換.

                        > KVC 按照鍵值路徑對象取值的時候,如果對象不包含對應的鍵值,會進入對象內部查找對象屬性.

                        > KVC 取嵌套很深的路徑的時候,只要一個路徑就能把想要的對象取出來,能幫我們很方便的編碼.

            > 使用前提:

使用了KVC,如果有訪問器方法,則運行時會在訪問器方法中調用will/didChangeValueForKey:方法;

如果沒用訪問器方法,運行時會在setValue:forKey方法中調用will/didChangeValueForKey:方法

            > 使用場景:

                        > 字典轉模型: setValuesForKeysWithDictionary

                        > 模型轉字典: dictionaryWithValuesForKeys

補充:>>>>>>>>>>>>>>>>>>>以下為轉載大神文章<<<<<<<<<<<<<<<<<<<<<<

>>>> 基本概念

1. 它是一種可以直接通過字元串的名字(key)來訪問類屬性的機制。而不是通過調用Setter、Getter方法訪問。

     2. 在應用程式中實現鍵-值編碼相容性是一項重要的設計原則。存取方法可以加強合適的數據封裝,而鍵-值編碼方法在多數情況下可簡化程式代碼。

     3. 鍵-值編碼支持帶有對象值的屬性,同時也支持純數值類型和結構。非對象參數和返回類型會被識別並自動封裝/解封。

          使用 KVC 為對象賦值或者取值時,需要知道準確的鍵值, 相比較點語法,KVC 是一種間接的傳遞方式,這種方式有利於

          對象解耦,讓對象彼此之間的耦合度不會太高。

>>>> 設置和訪問

1.鍵/值編碼中的基本調用包括 -valueForKey: 和 -setValue:forkey: 這兩個方法,它們以字元串的形式向對象發送消息,字元串為屬性名.

      2.是否存在 setter、getter 方法, 若存在優先調用相應方法;若不存在,它將在內部查找名為 _key 或 key 的實例變數。

      3.通過 KVC 設置對象,此對象會 retain。

      4.通過 setValue:forKey: 設置對象的值,或通過 valueForKey 來獲取對象的值時,如若對象的實例變數為基本數據類型時 ( char,int,float,BOOL ) ,我們需要對數據進行封裝。

      5.賦值語句 setValue:forKey: 是給對象當前的屬性賦值,而 setValue:forKeyPath: 是按照對象的層級關係為其中的屬性賦值。 forKeyPath可以替代forKey,但是forKey不能替代forKeyPath。

>>>> KVC 中常用的方法

       > 獲取值

              valueForKey:,傳入NSString屬性的名字。

              valueForKeyPath:,傳入NSString屬性的路徑,xx.xx形式。

              valueForUndefinedKey它的預設實現是拋出異常,可以重寫這個函數做錯誤處理。

       > 修改值

              setValue:forKey:

              setValue:forKeyPath:  m

              setValue:forUndefinedKey:

              setNilValueForKey: 當對非類對象屬性設置nil時,調用,預設拋出異常。

       > 一對多關係成員的情況

             mutableArrayValueForKey:有序一對多關係成員  NSArray

mutableSetValueForKey:無序一對多關係成員  NSSet

>>>> KVC的實現細節

         搜索Setter、Getter方法,這一部分比較重要,能讓你瞭解到KVC調用之後,到底是怎樣獲取和設置類成員值的。

       >  搜索簡單的成員 如:基本類型成員,單個對象類型成員:NSInteger,NSString*成員。

     a. setValue:forKey的搜索方式:

         1. 首先搜索set<Key>:方法

           如果成員用@property,@synthsize處理,因為@synthsize告訴編譯器自動生成set<Key>:格式的setter方法,

           所以這種情況下會直接搜索到。註意:這裡的<Key>是指成員名,而且首字母大寫。下同。

        2. 上面的setter方法沒有找到,那麼類方法accessInstanceVariablesDirectly返回YES(註:這是NSKeyValueCodingCatogery中實現的類方法,預設實現為返回YES)。

            那麼按_<key>,_is<Key>,<key>,is<key>的順序搜索成員名。

        3. 如果找到就去設置成員的值,如果沒有就去調用setValue:forUndefinedKey:。

     b. valueForKey:的搜索方式:

        1. 首先按get<Key>、<key>、is<Key>的順序查找getter方法,找到直接調用。如果是bool、int等內建值類型,會做NSNumber的轉換。

        2. 上面的getter沒有找到,查找countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes格式的方法。

            如果countOf<Key>和另外兩個方法中的一個找到,那麼就會返回一個可以響應NSArray所有方法的代理集合(collection proxy object)。發送給這個代理集合(collection proxy object)的NSArray消息方法,就會以countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes這幾個方法組合的形式調用。還有一個可選的get<Key>:range:方法。

        3. 還沒查到,那麼查找countOf<Key>、enumeratorOf<Key>、memberOf<Key>:格式的方法。

           如果這三個方法都找到,那麼就返回一個可以響應NSSet所有方法的代理集合(collection proxy object)。發送給這個代理集合(collection proxy object)的NSSet消息方法,就會以countOf<Key>、enumeratorOf<Key>、memberOf<Key>:組合的形式調用。

        4. 還是沒查到,那麼如果類方法accessInstanceVariablesDirectly返回YES,那麼按_<key>,_is<Key>,<key>,is<key>的順序直接搜索成員名。

        5. 再沒查到,調用valueForUndefinedKey:。

  > 查找有序集合成員,比如NSMutableArray

    mutableArrayValueForKey:搜索方式如下:

     1. 搜索insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:或者insert<Key>:atIndexes、remove<Key>AtIndexes:格式的方法。

        如果至少一個insert方法和至少一個remove方法找到,那麼同樣返回一個可以響應NSMutableArray所有方法的代理集合。那麼發送給這個代理集合的NSMutableArray消息方法,以insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:、insert<Key>:atIndexes、remove<Key>AtIndexes:組合的形式調用。還有兩個可選實現的介面:replaceObjectIn<Key>AtIndex:withObject:、replace<Key>AtIndexes:with<Key>:。

     2. 否則,搜索set<Key>:格式的方法,如果找到,那麼發送給代理集合的NSMutableArray最終都會調用set<Key>:方法。

      也就是說,mutableArrayValueForKey取出的代理集合修改後,用set<Key>:重新賦值回去。這樣做效率會差很多,所以推薦實現上面的方法。

     3. 否則,那麼如果類方法accessInstanceVariablesDirectly返回YES,那麼按_<key>,<key>的順序直接搜索成員名。如果找到,那麼發送的NSMutableArray消息方法直接轉交給這個成員處理。

     4. 再找不到,調用setValue:forUndefinedKey:。

 > 搜索無序集合成員,如:NSSet。

   mutableSetValueForKey:搜索方式如下:

    1. 搜索add<Key>Object:、remove<Key>Object:或者add<Key>:、remove<Key>:格式的方法,如果至少一個insert方法和至少一個remove方法找到,那麼返回一個可以響應NSMutableSet所有方法的代理集合。那麼發送給這個代理集合的NSMutableSet消息方法,以add<Key>Object:、remove<Key>Object:、add<Key>:、remove<Key>:組合的形式調用。還有兩個可選實現的介面:intersect<Key>、set<Key>:。

    2. 如果reciever是ManagedObejct,那麼就不會繼續搜索了。

    3. 否則,搜索set<Key>:格式的方法,如果找到,那麼發送給代理集合的NSMutableSet最終都會調用set<Key>:方法。也就是說,mutableSetValueForKey取出的代理集合修改後,用set<Key>:重新賦值回去。這樣做效率會差很多,所以推薦實現上面的方法。

    4. 否則,那麼如果類方法accessInstanceVariablesDirectly返回YES,那麼按_<key>,<key>的順序直接搜索成員名。如果找到,那麼發送的NSMutableSet消息方法直接轉交給這個成員處理。

    5. 再找不到,調用setValue:forUndefinedKey:。

>>>> KVC還提供了下麵的功能

    > 值的正確性核查

        KVC提供屬性值確認的API,它可以用來檢查set的值是否正確、為不正確的值做一個替換值或者拒絕設置新值並返回錯誤原因。

        實現核查方法為如下格式:validate<Key>:error:如:

            [cpp] view plain copy

            在CODE上查看代碼片派生到我的代碼片

            -(BOOL)validateName:(id *)ioValue error:(NSError **)outError

            {

                // The name must not be nil, and must be at least two characters long.

                if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2]) {

                    if (outError != NULL) {

                        NSString *errorString = NSLocalizedStringFromTable(

                        @"A Person's name must be at least two characters long", @"Person",

                        @"validation: too short name error");

                        NSDictionary *userInfoDict =

                        [NSDictionary dictionaryWithObject:errorString

                        forKey:NSLocalizedDescriptionKey];

                        *outError = [[[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN

                        code:PERSON_INVALID_NAME_CODE

                        userInfo:userInfoDict] autorelease];

                    }

                    return NO;

                }

                return YES;

            }

     調用核查方法:

        validateValue:forKey:error:,預設實現會搜索 validate<Key>:error:格式的核查方法,找到則調用,未找到預設返回YES。

        註意其中的記憶體管理問題。

>>>> 集合操作

   集合操作通過對valueForKeyPath:傳遞參數來使用,一定要用在集合(如:array)上,否則產生運行時刻錯誤。其格式如下:

     Left keypath部分:需要操作對象路徑。

     Collectionoperator部分:通過@符號確定使用的集合操作。

     Rightkey path部分:需要進行集合操作的屬性。

   >>>> 數據操作

        @avg:平均值

        @count:總數

        @max:最大

        @min:最小

        @sum:總數

        確保操作的屬性為數字類型,否則運行時刻錯誤。

   5.2 對象操作

   針對數組的情況

       @distinctUnionOfObjects:返回指定屬性去重後的值的數組

       @unionOfObjects:返回指定屬性的值的數組,不去重

       屬性的值不能為空,否則產生異常。

   > 數組操作

     針對數組的數組情況

         @distinctUnionOfArrays:返回指定屬性去重後的值的數組

         @unionOfArrays:返回指定屬性的值的數組,不去重

         @distinctUnionOfSets:同上,只是返回值為NSSet

>>>>  效率問題

 相比直接訪問KVC的效率會稍低一點,所以只有當你非常需要它提供的可擴展性時才使用它。

>>>>代碼實現以上知識:

 1)直接賦值

    使用KVC 可以對對象的某個屬性進行賦值。如下麵的代碼:

    假定現在我們有一個Person 類,類中包含兩個屬性:一個是只讀的name 屬性,一個是Number類型的age屬性。

         @interface Person : NSObject

         @property(nonatomic,copy,readonly)NSString* name;

         @property(nonatomic,assign)NSNumber *age;

         @end

    當我們定義了屬性的時候,系統就為我們自動的生成了setter 和getter 方法。我們可以通過setter 和getter方法,或讀取或寫入數值。當然我們也可以用KVC 的方式進行讀寫數據。

         @interface ViewController ()

         @end

         @implementation ViewController

         - (void)viewDidLoad

         {

             [super viewDidLoad];

             Person *person=[[Person alloc] init];

             [person setValue:@"20" forKey:@"age"];

             [person setValue:@"張依依" forKey:@"name"];

             NSLog(@"person 的名字是%@",person.name);

             NSLog(@"person 的年領是%@",[person valueForKey:@"age"]);

         }

         @end

    總結: 只讀的屬性怎麼可以賦值? 還有age屬性明明是NSNumber類型的,怎麼可以把字元串賦給它?!沒錯,這就是我想說的,KVC 不但能夠賦值,而且還能破壞只讀的特性。當然這隻是我們需要註意的一個細節,更重要的是KVC 有自動裝箱

        (自動類型轉換)的功能,我們不需要去轉換類型了。由於開發過程中數據領域是字元串的天下,所以這個自動裝箱的功能的確是極好的。

 2)支持鍵值路徑

什麼叫支持鍵值路徑?說白了就是支持嵌套。假如現在有一個書籍類,類中包含了書籍的名稱name。

書籍可以被Person所擁有(就是可以作為person的屬性)

         @interface Book : NSObject

         @property(nonatomic,copy)NSString* name;

         @end

    那麼我們就可以這樣來用

         Person *person=[[Person alloc] init];

         Book *myBook=[[Book alloc] init];

         person.book=myBook;

         [person setValue:@"程式員攤煎餅指南" forKeyPath:@"book.name"];

         NSLog(@"%@",[person valueForKeyPath:@"book.name"]);

    這裡的key直接使用點局分開就好了,註意一下:這裡使用的時keyPath,

    當然在 “ 1)屬性賦值” 中我們也可以使用keyPath,只不過再不必要的情況下使用keyPath會浪費性能而已。

   1.路徑

     除了通過鍵設值或取值外, 鍵/值編碼還支持指定路徑設值或取值,像文件系統一樣, 用“ . ”號隔開:

        [book setValue:@"比爾" forKeyPath:@"author.name"];

        NSNumber *price=[book valueForKeyPath:@"relativeBooks.price"]

   2.數組的整體操作

     如果向 NSArray 請求一個鍵值,它實際上會查詢數組中的每個對象來查找這個鍵值, 然後將查詢結果打包到另一

     個數組中並返回給你:

 

        // 獲取 Student 中所有 Book 的 name

        NSArray *names = [student.books valueForKeyPath:@"name"]; 或者

        NSArray *names = [student valueForKeyPath:@"books.name"];

        //註意:不能在鍵路徑中為數組添加索引,比如 @"books[0].name"

 3)支持操作符

    KVC的簡單運算

        //count

        NSString *count = [book valueForKeyPath:@"relativeBooks.@count"];

        NSLog(@"count : %@", count);

        //sum

        NSString *sum = [book valueForKeyPath:@"relativeBooks.@sum._price"];

        NSLog(@"sum : %@", sum);

        //avg

        NSString *avg = [book valueForKeyPath:@"relativeBooks.@avg._price"];

        NSLog(@"avg : %@", avg);

        //min

        NSString *min = [book valueForKeyPath:@"relativeBooks.@min._price"];

        NSLog(@"min : %@", min);

        //max

        NSString *max = [book valueForKeyPath:@"relativeBooks.@max._price"];

        NSLog(@"max : %@", max);

 4)錯誤攔截

    對於我們前端程式員來說,後端程式員有時也是一個troubleMaker。他總是給你傳遞一些很奇怪的東西。比如給你傳遞一個id 屬性,或者什麼都不給你傳。如果有這樣一個json文件 {“id”:"1"}。這是逼著我們把id作為數據模型的一個屬性的節奏啊!!老夫不願意啊!儘管作為屬性也不會報錯。屈服?還是抗爭?這是一個問題。但是好在前輩們已經給了我們答案。假如我們有一個Model類,類中的whoCare屬性就是本應命名為id 的屬性。我們還寫了一個字典轉模型的初始化方法。

        @interface Model : NSObject

        @property(nonatomic,strong)id whoCare;

        -(instancetype)initWithDict:(NSDictionary *)dict;

        @end

   那麼我們可以在.m文件中重寫 -(void)setValue:(id)value forUndefinedKey:(NSString *)key 方法。這個方法會在字典轉模型時,系統找不到同名的屬性時調用。所以我們可以再這個方法中進行錯誤攔截,併進行賦值操作,這樣就不會報錯了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 閉包是可以在代碼中被傳遞和使用的自包含功能模塊,它很像c和oc中的block,和.net中的lambdasbas表達式。 閉包可以捕獲和存儲其所在上下文中任意常量和變數的引用。 包裹著這些常量和變數的包俗稱閉包。Swift會為您管理在捕獲過程中涉及到的記憶體操作。下麵是閉包的3中表現形式 全局函數是一 ...
  • 1、產品設計圖 可以以6的長寬比 750*1134來設計。這些圖片用於描述app是什麼樣子的,這是app開發人員的開發參考。 2、產品切圖 將設計師將設計稿切成可以用來開發的圖 顏色值 iOS顏色值取 RGB各顏色的值比如某個色值,給予iOS開發的色值為 R:12 G:34 B:56 給出的值就是 ...
  • title: 帶你實現開發者頭條APP(四) 首頁優化(加入design包) tags: design,Toolbar,TabLayout,RecyclerView grammar_cjkRuby: true 一 、前言 上次模仿開發者頭條首頁實現了一個版本,給 "345大神,我的產品經理" 一看, ...
  • 1、彈框出現在屏幕中間位置 此方法可以添加文本框,輸入內容 2、彈框出現在屏幕底部(兩種方式的不同點在於代碼第一行最後的,底部是UIAlertControllerStyleActionSheet) ...
  • 最近解析些複雜的節點數據解析,用安卓自帶的json解析比較麻煩所以只能用Gson解析,所以從網上下了點demo來看看 http://blog.csdn.net/tkwxty/article/details/34474501這個看看還不錯 例子代碼如下 ...
  • 給EditText追加ChangedListener可以監聽EditText內容變化的監聽 如圖是效果圖 類似於過濾的一種實現 1 佈局也就是一個EditText,當EditText內容發生變化時(當輸入數字時)就會出現一個PopupWindow通過ChangedListener來顯示監聽 2 數據 ...
  • Android開發中,常常會用到color.xml顏色配置,好的顏色配置可以讓尼的應用讓人看起來賞心悅目! 不羅嗦,上圖先 該工程已經羅列了常用的顏色配置 附上工程鏈接:http://download.csdn.net/detail/geniuseoe2012/5816967 什麼?還沒找到尼想要的 ...
  • TNW中文站 4月8日報道 安卓操作系統的軟體開發語言是Java,而在過去幾年中,有關Java的版權,谷歌(微博)和甲骨文之間發生了長期的訴訟。最新外媒消息稱,谷歌正在考慮將蘋果開發的Swift作為未來安卓軟體開發的“一級”語言,此外Facebook、Uber等公司也開始越來越重視Swift的使用。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...