1. 程式人生 > >打造強大的BaseModel(2):讓Model實現自動對映,將字典轉化成Model

打造強大的BaseModel(2):讓Model實現自動對映,將字典轉化成Model

這篇文章將講述Model一項更高階也最常用的功能,讓Model實現自動對映–將字典轉化成Model(所有程式碼全由Swift實現)

將JSON轉化為Model的意義

在iOS開發中,基於Model的資料流起到了至關重要的作用。從網路獲取的資料需要進一步處理轉到成View可用的Model,再通過ViewController傳送給View展示出來,從View中反饋的資料也可以轉為為Model,再將Model轉化成JSON傳送給伺服器。通常開發過程中需要最頻繁處理的還是將JOSN轉化成對應的Model,目前市面上許多非常好用的JSON-Model庫,比如MJ大神的MJExtension,還有Matle及JSONModel。

目前我還從未在專案裡用到這些庫,有興趣的讀者可以自行去試試這些開源庫,也可以去看看它們的原始碼。這篇文章主要是討論如何用簡單的程式碼寫一個基類Model,讓子類可以自動實現從字典獲取資料再轉化為自身。功能並不算強大,但是還是比較實用的。

將字典轉化為Model這個過程中,最簡單便捷的情況就是字典的Key與Model的屬性名是一一對應的,這樣只要使用簡單的KVC即可完成JOSN-Model轉換。但是實際開發過程中很少出現這情況,也許你的命名風格和伺服器開發的同事的命名風格不一樣,也許同一個屬性名在不同的介面有不一樣的名字,總之很難達到這種理想的情況。我們最後還是要乖乖按伺服器的同事給的Key名來轉換。

先前我都是使用簡單的Dict[Key]的取值方式來實現JOSN-Model轉換,這種情況在Objc還是比較好用的,寫起來很方便,但是在Swift裡就完全行不通了,各種強制轉換寫起來很囉嗦很不爽。SwiftyJSON就是為了解決這種問題誕生的。用了SwiftyJSON看起來確實好了不少,但是還是要寫很多重複的程式碼來轉換,降低了開發效率。

使用KVC來實現字典-Model轉換

所以最好還是讓Model可以自動實現字典-Model對映。既然有這麼強大的KVC可以用,那為什麼不用呢?按照這個思路,我用Swift寫下了以下程式碼,先定義一個協議,裡面有一個靜態方法,目的是將一個字典轉化成一個Self物件

123 protocolMapAble{staticfunc mapModel(obj:AnyObject)->Self//將一個字典轉化成自己}

需要在GrandModel裡處理一些東西

123456789 //定義一個ModelclassGrandModel:NSObject{classvarselfMapDescription:[String:String]?{returnnil}required override init(){super.init()}

在extension裡面實現協議

1234567891011121314151617 extension GrandModel:MapAble{staticfunc mapModel(obj:AnyObject)->Self{let model=self.init()iflet mapTable=self.selfMapDescription{iflet dict=obj as?[String:AnyObject]{foritemindict{iflet key=mapTable[item.0]{print("key 為(item.0)將要被設成(mapTable[item.0),其值是 (item.1)")model.setValue(item.1,forKey:key)}}}}returnmodel}}

程式碼層次比較深,看起來有點亂,但總體邏輯卻很簡單。selfMapDescription是一個Class靜態屬性,它描述了字典的Key是怎麼和Model的屬性名是怎麼對映的。子類需要重寫這個屬性。

1 required override init()

這是一個構造器,並且標記為required,說明是必需的。作用是保證該類是可以初始化的,只有這樣extension裡的self.init()語句才不會報錯。因為如果子類也不提供構造器的話,那麼該類不能正常用構造器例項化,也就是不能用init()方法了。

12 let model=self.init()let mapTable=self.selfMapDescription

這個就比較好解釋了,在靜態方法裡面,self是一個Type型別,表示執行時的型別。它可以呼叫init()直接例項化一個執行時繼承於GrandModel的類。接下來的程式碼就比較簡單了,只要簡單將字典裡的Value用KVC一個一個給Model賦值就行了。賦值完成後再返回該物件

下面我們來看子類如何繼承該類,並且怎麼使用些功能

123456789101112131415161718192021 classDemoClass:GrandModel{varname:String?varage:Int?vargrade:Int?//需要重寫selfMapDescriptionoverride staticvarselfMapDescription:[String:String]?{return["sName":"name","iAge":"age","iGrade":"grade"]}}//下面來測試let demoDict=["sName":"Stan","iAge":"12","iGrade":"6"]vardemo=DemoClass()demo=DemoClass.mapModel(demoDict)print(demo)//列印結果:keysName將要被設成Optional("name"),其值是StankeyiGrade將要被設成Optional("grade"),其值是6沒有這個欄位-------gradekeyiAge將要被設成Optional("age"),其值是12沒有這個欄位-------age

這裡有奇怪的地方,明明DemoClass有兩個Int型別的屬性,但是又說找不到?其實在這裡參考第一篇文章就很容易明白,這兩個屬性是Int?的型別的,而Objc裡面是沒有於之對應的型別的,可以在這個屬性前面加上@objc試試

可以看見XCode報錯了。Int?不能表現為Objc型別,所以在Objc執行時裡面是找不到與之對應的型別,自然不能加上@Objc標記了。
那麼怎麼辦?其實很簡單,給它一個初始值就行了,在執行時可以將其轉化成Objc的型別

123456789101112 classDemoClass:GrandModel{varname:String?varage:Int=0vargrade:Int=0//後面的省略了}//下面列印的結果完全符合預期keysName將要被設成Optional("name"),其值是StankeyiGrade將要被設成Optional("grade"),其值是6keyiAge將要被設成Optional("age"),其值是12Optional(name)DemoClass:["age":12,"grade":6,"name":Stan]

現在打印出的結果是完全符合我們的預期了。KVC的強大之處在這裡表現得淋漓盡致,我們根本不需要理會這些基本資料型別,KVC可以幫我們搞定。

兩個問題和解決方案

但是目前還有兩個問題:一是如果介面有多種風格的屬性名,比如這個介面將UserName,另一個叫做sUserName,又或者叫userName等,多種不同的屬性名。至少我現在在做的專案至少有三種類型。其實這個非常簡單,直接把所有屬性的名字新增到selfMapDescription裡面就行

1234 //需要重寫selfMapDescriptionoverride staticvarselfMapDescription:[String:String]?{return["sName":"name","iAge":"age","iGrade":"grade","UserName":"userName","sUserName":"userName","userName":"userName"]//將這個三屬性名全部對映到userName}

第二個問題,如果返回的資料裡嵌套了複雜型別,比如Array,Dictionary或者是其他物件等,KVC就不能幫你自動轉了

1234567891011121314151617181920212223242526272829303132333435363738 classDemoOther:GrandModel{varuserName:String?override staticvarselfMapDescription:[String:String]?{return["userName":"userName"]}}classDemoClass:GrandModel{varname:String?varage:Int=0vargrade:Int=0varuserName:String?varotherClass:DemoOther?varotherClasses:[DemoOther]?//需要重寫selfMapDescriptionoverride staticvarselfMapDescription:[String:String]?{return["sName":"name","iAge":"age","iGrade":"grade","UserName":"userName","sUserName":"userName","userName":"userName","DemoOther":"otherClass","DemoOthers":"otherClasses"]}}//下面來測試let demoDict=["sName":"Stan","iAge":"12","iGrade":"6","UserName":"userName","DemoOther":["userName":"OtherUserName"],"DemoOthers":[["userName":"OtherUserName1"],["userName":"OtherUserName2"]]]vardemo=DemoClass()demo=DemoClass.mapModel(demoDict)print(demo.otherClass)//打印出來是這東西,//Optional({ userName = OtherUserName;})

打印出的資料雖然看起來好像是正確的,但是其實格式是錯誤的。也就是說,KVC不能轉化複雜的或者自定義的物件。只能自己手動寫了。

1234 demo.otherClass=DemoOther.mapModel(demoDict["DemoOther"]!)print(demo.otherClass)//打印出來是這東西,//**Optional(DemoOther:["userName": OtherUserName])**

這下打印出的東西就符合預期了,陣列物件也一樣,用個迴圈來轉化即可。

總結

上面的輕量型字典-Model轉換方案雖然在功能上不能和第三方的Json-Model庫相比,但對於大部分專案來說,還是夠用了。使用KVC帶來的效能上的損失我還是可以接受的,我討厭寫重複的程式碼。好了,以上就是第二篇的全部內容。

相關推薦

打造強大BaseModel2Model實現自動對映字典化成Model

這篇文章將講述Model一項更高階也最常用的功能,讓Model實現自動對映–將字典轉化成Model(所有程式碼全由Swift實現) 將JSON轉化為Model的意義 在iOS開發中,基於Model的資料流起到了至關重要的作用。從網路獲取的資料需要進一步處理轉到成View可用的

打造強大BaseModel3Model實現自動歸檔

本文是「打造強大的BaseModel」的篇三篇,第一篇文章請見此:讓Model自我描述 。第二篇文章請見此:讓Model自動轉換。相對於讓Model實現自我描述和自動轉換,讓Model實現自動歸檔會難一點(事實後來我發現一點也不難)。我相信能夠好好看完這三篇文章的人,絕對是有大

打造強大BaseModel1Model自我描述

前言 從事iOS開發已經兩年了,從一無所知到現在能獨立帶領團隊完成一系列APP的開發,網路上的大神給了我太多的幫助。他們無私地貢獻自己的心得和經驗,寫出了一篇篇精美的文章。現在我也開始為大家貢獻自己的心得,把它寫成一系列iOS開發技巧系列文章。 這一系列文章都乾貨十足,希望各位

Istio 運維實戰系列2人頭大的『無頭服務』-上

本系列文章將介紹使用者從 Spring Cloud,Dubbo 等傳統微服務框架遷移到 Istio 服務網格時的一些經驗,以及在使用 Istio 過程中可能遇到的一些常見問題的解決方法。 ## 什麼是『無頭服務』? 『無頭服務』即 Kubernetes 中的 Headless Service。Servic

F#與ASP.NET2使用F#實現基於事件的非同步模式

在上一篇文章中,我們的簡單討論了.NET中兩種非同步模型以及它們在異常處理上的區別,並且簡單觀察了ASP.NET MVC 2中非同步Action的編寫方式。從中我們得知,ASP.NET MVC 2的非同步Action並非使用了傳統基於Begin/End的非同步程式設計模型,而是另一種基於事件的非同步模式。此外

Xilinx Vivado的使用詳細介紹2綜合、實現、管腳分配、時鐘設定、燒寫

前面一篇介紹了從新建工程一直到編寫程式碼進行行為模擬,這篇繼續進行介紹。 修改器件型號 新建工程時選擇過器件型號,如果新建好工程後需要修改型號,可以選擇選單Tools - Project Settings。 彈出視窗中,點選Project Device右側的按鈕

自定義堆2通過堆實現優先佇列

學習堆、優先佇列之間的關係。   普通佇列:先進先出;後進後出。 優先佇列:出隊順序和入隊順序無關,和優先順序相關。     入隊 出隊(拿出最大元素) 之前自定義的普通線性結

打破國外壟斷開發中國人自己的程式語言2使用監聽器實現計算器

上一篇:實現可以解析表示式的計算器 本文已經同步到公眾號「極客起源」,輸入379404開始學習!   本文是《打破國外壟斷,開發中國人自己的程式語言》系列文章的第2篇。本系列文章的主要目的是教大家學會如何從零開始設計一種程式語言(marvel語言),並使用marvel語言開發一些真實的專案,如移動A

打造強大BaseModel4使用Swift反射

而這篇文章則討論了Swift的反射功能,與iOS Runtime不一樣,Swift的反射用了另一套API,實現機制也完全不一樣,倒是和目前其他的面嚮物件語言有些相似,比如C#和Java。不過Swift作為一門很新的語言,目前正在高速發展中,其反射功能和和主流的高階語言還沒法比

Windows Phone開發2豎立自信初試鋒茫

一鍵 優秀 保持 知識 sdn ant emulator 一個 動畫 上一篇文章中,我們聊了一些“大炮”話題,從這篇文章開始,我們一起來學習WP開發吧。 一、我們有哪些裝備。 安裝完VS 學習版 for WP後,也連同SDK一並安裝了,不必像安卓那樣,安裝JDK,下載

TCP/IP協議2網絡設備

數據包 服務器 網絡設備 風暴 二層交換機 不同的 中繼器 tcp/ip 解決 1、中繼器(Repeater) 中繼器工作在OSI的一層,我們知道,超5類線的傳輸距離最大為100米,超過這個距離信號就會衰減,中繼器就是為了防止信號變差,將網絡信號進行再生和重定時。 2、

MongoDB2 增刪改操作

db nosql mongo 增刪改 curd 附加命令:1、進入前端操作命令./mongo [ip:端口]說明:默認會自動選本地,端口270172、顯示所有的庫> show dbs; 或者 show databases;3、選擇庫> use 庫名;4、顯示庫所有的集合&g

數據清洗小記2全角數字轉換半角數字

大局觀 山東 轉載 亞洲 pop rpm包 stats mod 法律 原創作品。出自 “深藍的blog” 博客,歡迎轉載,轉載時請務必註明出處,否則有權追究版權法律責任。深藍的blog:http://blog.csdn.net/huangyanlong/article/d

python每日一類2platform

獲得 min def glob model implement 匯總 uname 信息 根據官方文檔的解釋(https://docs.python.org/3.5/library/platform.html#module-platform): 學習其他人的代碼如下: #

springBoot2Properties和YAML配置文件

springboot springboot的properties和yaml配置文件 一、配置文件的生效順序,會對值進行覆蓋1. @TestPropertySource 註解2. 命令行參數3. Java系統屬性(System.getProperties())4. 操作系統環境變量5. 只有在rando

Java學習2鍵盤錄入的內容保存到指定文件中

stream exce 創建 txt 關閉 如果 下午 line 再次 要求:保存鍵盤錄入的內容,當鍵盤輸入end時,錄入結束。 1 /** 2 * 保存鍵盤輸入,並以end結束 3 * 4 * @author xcx 5 * @time 2017年6

初識vue 2.02路由與組件

組件化 script -128 watch css image 暫時 效果 默認 1,在上一篇的創建工程中,使用的的模版 webpack-simple 只是創建了一個簡單的demo,並沒有組件和路由功能,此次采用了webpack模版,自動生成組件和路由。^_^ 在模版初始

python函數2函數進階

int splay 基本 源文件 tuple [0 執行 內容 理念 昨天說了函數的一些最基本的定義,今天我們繼續研究函數。今天主要研究的是函數的命名空間、作用域、函數名的本質、閉包等等 預習: 1、寫函數,用戶傳入修改的文件名,與要修改的內容,執行函數,完成整個文件

記Angular與Django REST框架的一次合作2前端組件化——Angular

服務器 信息 outer demo cli 組成 控制 set 根據 註:這是這個系列的第二部分,主要集中在Angular的使用方面。之前使用過AngularJS(Angular 1.x),混在Django的模板中使用,這些頁面一般完全是結果展示頁。在有Django表單輸入

Unity3d使用心得2Unity3d 動態下載動畫資源——AnimationClip 的使用 - 斯瑪特琦

通過 dsm color 解決 con content 資源 sse popu 引言: 在使用 Unity3d 開發微端、或者網頁遊戲的時候常常須要將資源打包成 AssetBundle ,然後通過 www 的方式動態的下載資源。今天要分享的是我再動態下