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是一個(gè)字典,調(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)
}
幾個(gè)代碼點(diǎn)需要著重分析理解下
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,提示錯(cuò)誤信息并return。
從Type繼承圖關(guān)系可以看到還有很多其它Type類型,如元組這種類型等,主要應(yīng)用于model定義的存儲(chǔ)屬性,所以這里要區(qū)分開,不要搞混了。
2)let model = _ptr()
這里的model是當(dāng)前定義的模型實(shí)例地址即指針,是UnsafeMutableRawPointer類型,后面在進(jìn)行set賦值的時(shí)候會(huì)通過運(yùn)算符重載將其轉(zhuǎn)換為UnsafeMutablePointer<T>指針類型。
3)for property in properties {}
遍歷定義的存儲(chǔ)屬性,對(duì)每一個(gè)存儲(chǔ)屬性進(jìn)行賦值
具體分析下里面的賦值代碼:
a)、
// 這里是獲取key,返回的key是一個(gè)字符串或者數(shù)組
let key = mt.modelKey(from: property.name,kj_modelKey(from: property))
底層方法調(diào)用流程圖:

b)、
// 將json值轉(zhuǎn)換為用戶自定義model里面實(shí)現(xiàn)kj_modelValue方法的值,如果用戶沒有實(shí)現(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是不相等的,比如用戶類型寫錯(cuò)了或者也沒有實(shí)現(xiàn)kj_modelValue方法,類型無法匹配
if Swift.type(of: newValue) == propertyType {
// 會(huì)把指針model傳入會(huì)被轉(zhuǎn)換為UnsafeMutablePointer<T>類型進(jìn)行賦值操作
property.set(newValue, for: model)
continue
}
核心賦值操作都是調(diào)用property.set(newValue, for: model),我們分析下底層這里是如何實(shí)現(xiàn)的:
為了能更直觀的展示調(diào)用過程,我們這里還是用流程圖:

看完這里你是不是會(huì)有一個(gè)疑問,就是如果類型不匹配怎么辦,即應(yīng)該有類型失敗的一個(gè)判斷,比如我們定義的存儲(chǔ)屬性是String,但是json返回的是一個(gè)Array數(shù)組?看流程圖的最后一步,as?就是類型轉(zhuǎn)換的一個(gè)判斷,如果類型不匹配是不會(huì)通過指針寫入內(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)換過程,可實(shí)現(xiàn)這2個(gè)方法
至此整個(gè)JSON解析過程我們就分析完了
很多時(shí)候我們?cè)诳匆恍┑谌綆煸创a的時(shí)候有時(shí)候會(huì)云里霧里的,這個(gè)時(shí)候可再去看看作者在github上面介紹的這個(gè)庫的功能點(diǎn),你就能豁然開朗,因?yàn)槲覀兤綍r(shí)在項(xiàng)目中用的時(shí)候并不是所有功能點(diǎn)都能用到,看實(shí)際需求。
參考文獻(xiàn):
https://github.com/kakaopensource/KakaJSON
http://www.itdecent.cn/p/9ca7529306b2