1.代碼結(jié)構(gòu)
2.JSON解析出Model具體的流程
下面是官方demo的例子,我們拿此例子解析
import KakaJSON
struct Repo: Convertible {
var name: String?
var url: URL?
}
let json = [
"name": "KakaJSON",
"url": "https://github.com/kakaopensource/KakaJSON"
]
let repo = json.kj.model(Repo.self)
print(repo)
流程
1)調(diào)用json字典的kj屬性
public extension KJGenericCompatible {
static var kj: KJGeneric<Self, T>.Type {
get { return KJGeneric<Self, T>.self }
set {}
}
var kj: KJGeneric<Self, T> {
get { return KJGeneric(self) }
set {}
}
}
2)Base是一個字典阁簸,調(diào)用model方法
public extension KJGeneric where Base == [String: T] {
/// JSONObject -> Model
func model<M: Convertible>(_ type: M.Type) -> M {
return model(type: type) as! M
}
/// JSONObject -> Model
func model(type: Convertible.Type) -> Convertible {
return base.kj_fastModel(type)
}
}
3)調(diào)用Base的kj_fastModel方法
extension Dictionary where Key == String {
func kj_fastModel(_ type: Convertible.Type) -> Convertible {
var model: Convertible
if let ns = type as? NSObject.Type {
model = ns.newConvertible()
} else {
model = type.init()
}
model.kj_convert(from: self)
return model
}
........
}
4)賦值操作核心代碼
mutating func kj_convert(from json: [String: Any]) {
guard let mt = Metadata.type(self) as? ModelType else {
Logger.warnning("Not a class or struct instance.")
return
}
guard let properties = mt.properties else {
Logger.warnning("Don't have any property.")
return
}
// get data address
let model = _ptr()
kj_willConvertToModel(from: json)
// enumerate properties
for property in properties {
// key filter
let key = mt.modelKey(from: property.name,
kj_modelKey(from: property))
// value filter
guard let newValue = kj_modelValue(
from: json.kj_value(for: key),
property)~! else { continue }
let propertyType = property.dataType
// if they are the same type, set value directly
if Swift.type(of: newValue) == propertyType {
property.set(newValue, for: model)
continue
}
// Model Type have priority
// it can return subclass object to match superclass type
if let modelType = kj_modelType(from: newValue, property),
let value = _modelTypeValue(newValue, modelType, propertyType) {
property.set(value, for: model)
continue
}
// try to convert newValue to propertyType
guard let value = Values.value(newValue,
propertyType,
property.get(from: model)) else {
property.set(newValue, for: model)
continue
}
property.set(value, for: model)
}
kj_didConvertToModel(from: json)
}
幾個代碼點需要著重分析理解下
1)guard let mt = Metadata.type(self) as? ModelType
Metadata.type(self)是獲取當(dāng)前model的類型BaseType
首先我們看下各種Type的繼承關(guān)系圖:
我們定義的model要么是類class要么是結(jié)構(gòu)體struct肮帐,它們都繼承ModelType咖驮,所以這里判斷model的類型是ClassType或者StructType,如果定義的model不是這2種Type训枢,提示錯誤信息并return托修。
從Type繼承圖關(guān)系可以看到還有很多其它Type類型,如元組這種類型等恒界,主要應(yīng)用于model定義的存儲屬性睦刃,所以這里要區(qū)分開,不要搞混了十酣。
2)let model = _ptr()
這里的model是當(dāng)前定義的模型實例地址即指針涩拙,是UnsafeMutableRawPointer類型际长,后面在進(jìn)行set賦值的時候會通過運算符重載將其轉(zhuǎn)換為UnsafeMutablePointer<T>指針類型。
3)for property in properties {}
遍歷定義的存儲屬性兴泥,對每一個存儲屬性進(jìn)行賦值
具體分析下里面的賦值代碼:
a)工育、
// 這里是獲取key,返回的key是一個字符串或者數(shù)組
let key = mt.modelKey(from: property.name,kj_modelKey(from: property))
底層方法調(diào)用流程圖:
b)搓彻、
// 將json值轉(zhuǎn)換為用戶自定義model里面實現(xiàn)kj_modelValue方法的值如绸,如果用戶沒有實現(xiàn)kj_modelValue,那么直接返回jsonValue
guard let newValue = kj_modelValue(
from: json.kj_value(for: key),
property)~! else { continue }
底層方法調(diào)用流程圖:
c)旭贬、
// 如果它們類型相同直接賦值怔接,比如Any.Type和String.Type是不相等的,比如用戶類型寫錯了或者也沒有實現(xiàn)kj_modelValue方法稀轨,類型無法匹配
if Swift.type(of: newValue) == propertyType {
// 會把指針model傳入會被轉(zhuǎn)換為UnsafeMutablePointer<T>類型進(jìn)行賦值操作
property.set(newValue, for: model)
continue
}
核心賦值操作都是調(diào)用property.set(newValue, for: model)扼脐,我們分析下底層這里是如何實現(xiàn)的:
為了能更直觀的展示調(diào)用過程,我們這里還是用流程圖:
看完這里你是不是會有一個疑問奋刽,就是如果類型不匹配怎么辦谎势,即應(yīng)該有類型失敗的一個判斷,比如我們定義的存儲屬性是String杨名,但是json返回的是一個Array數(shù)組脏榆?看流程圖的最后一步,as?就是類型轉(zhuǎn)換的一個判斷台谍,如果類型不匹配是不會通過指針寫入內(nèi)存的须喂。
d)、
// 如果上面都還沒有賦值成功趁蕊,那么就進(jìn)行類型轉(zhuǎn)換
guard let value = Values.value(newValue,
propertyType,
property.get(from: model)) else {
// 類型轉(zhuǎn)換失敗坞生,用newValue直接進(jìn)行賦值,如果失敗交給as掷伙?去處理
property.set(newValue, for: model)
continue
}
e)是己、
kj_willConvertToModel(from: json)
kj_didConvertToModel(from: json)
當(dāng)有需要監(jiān)聽轉(zhuǎn)換過程,可實現(xiàn)這2個方法
至此整個JSON解析過程我們就分析完了
很多時候我們在看一些第三方庫源碼的時候有時候會云里霧里的任柜,這個時候可再去看看作者在github上面介紹的這個庫的功能點卒废,你就能豁然開朗,因為我們平時在項目中用的時候并不是所有功能點都能用到宙地,看實際需求摔认。
參考文獻(xiàn):
https://github.com/kakaopensource/KakaJSON
http://www.reibang.com/p/9ca7529306b2