SmartCodable - Swift數(shù)據(jù)解析的智能解決方案

???github SmartCodable 看起來還不錯(cuò)?給個(gè)star?吧,急需支持???

SmartCodable - Swift數(shù)據(jù)解析的智能解決方案

SmartCodable 是一個(gè)基于Swift的Codable協(xié)議的數(shù)據(jù)解析庫,旨在提供更為強(qiáng)大和靈活的解析能力。通過優(yōu)化和擴(kuò)展Codable的標(biāo)準(zhǔn)功能,SmartCodable 有效地解決了傳統(tǒng)解析過程中的常見問題,并提高了解析的容錯(cuò)性和靈活性。

為何選擇SmartCodable?

在使用標(biāo)準(zhǔn)的Codable進(jìn)行數(shù)據(jù)解析時(shí),開發(fā)者常常會(huì)遇到諸如鍵不存在、類型不匹配或值為null等問題,這些問題往往會(huì)導(dǎo)致整個(gè)解析過程的失敗,并拋出異常。SmartCodable 針對這些挑戰(zhàn)提供了智能化的解決方案,確保解析過程的健壯性和流暢性。

主要特性

  • 增強(qiáng)的錯(cuò)誤處理:當(dāng)遇到鍵不存在、類型不匹配或值為null等問題時(shí),不會(huì)立即中斷解析,而是提供了更為靈活的處理選項(xiàng)。
  • 值類型轉(zhuǎn)換:如果目標(biāo)類型與實(shí)際類型不符但可以進(jìn)行有意義的轉(zhuǎn)換,SmartCodable 會(huì)自動(dòng)轉(zhuǎn)換值類型,確保數(shù)據(jù)的正確解析。
  • 默認(rèn)值填充:當(dāng)某個(gè)屬性無法解析時(shí),SmartCodable 允許自動(dòng)填充該屬性類型的默認(rèn)值,例如將Bool類型的字段默認(rèn)設(shè)為false,從而避免了整個(gè)解析過程的失敗。
  • 兼容性和靈活性SmartCodable 完全兼容標(biāo)準(zhǔn)的Codable協(xié)議,并在此基礎(chǔ)上提供更多的定制化選項(xiàng),適應(yīng)更復(fù)雜和多變的數(shù)據(jù)解析需求。

解析效率

image.png

使用這樣的數(shù)組,數(shù)組的元素項(xiàng)分別設(shè)置為: 100個(gè),1000個(gè),10000個(gè)。分別對這五種解析方案進(jìn)行解析耗時(shí)的統(tǒng)計(jì)。

[
    {
        "name": "Anaa Airport",
        "iata": "AAA",
        "icao": "NTGA",
        "coordinates": [-145.51222222222222, -17.348888888888887],
        "runways": [
            {
                "direction": "14L/32R",
                "distance": 1502,
                "surface": "flexible"
            }
        ]
    }
]

理論上SmartCodable的解析效率是低于Codable的。如果不解析 runways ,就是如此。
SmartCodable對于枚舉項(xiàng)的解析更加高效。所以在本次數(shù)據(jù)對比中,解析效率最高,甚至高于Codable。

作者使用的是單元測試中的 measure 函數(shù)進(jìn)行性能測算。

struct Smart: SmartCodable {
    
    var name: String?
    var iata: String?
    var icao: String?
    var coordinates: [Double]?
    var runways: [Runway]?
    
    struct Runway: SmartCodable {
        var direction: String?
        var distance: Int?
        var surface: Surface?
    }
}

func testSmart() {
    measure {
        guard let objects = [Smart].deserialize(data: data)  else {
            return
        }
        XCTAssertEqual(objects.count, count)
    }
}

Demo工程中提供了測試用例,請自行下載工程代碼,訪問 Tests.swift 文件。

HandyJSON vs Codable

CodableHandyJSON是兩種常用的方法。

  • HandyJSON 使用Swift的反射特性來實(shí)現(xiàn)數(shù)據(jù)的序列化和反序列化。該機(jī)制是非法的,不安全的, 更多的細(xì)節(jié),可以訪問 HandyJSON 的466號issue.

  • Codable 是Swift標(biāo)準(zhǔn)庫的一部分,提供了一種聲明式的方式來進(jìn)行序列化和反序列化,它更為通用。

比較這兩者在性能方面的差異需要考慮不同的數(shù)據(jù)類型和場景。一般而言,Codable在以下情況下可能具有比HandyJSON更低的解析耗時(shí):

  1. 標(biāo)準(zhǔn)的JSON結(jié)構(gòu): 當(dāng)解析標(biāo)準(zhǔn)且格式良好的JSON數(shù)據(jù)時(shí),Codable通常表現(xiàn)出較好的性能。這是因?yàn)?code>Codable是Swift標(biāo)準(zhǔn)庫的一部分,得到了編譯器的優(yōu)化。
  2. 復(fù)雜數(shù)據(jù)模型: 對于包含多層嵌套和復(fù)雜數(shù)據(jù)結(jié)構(gòu)的JSON,Codable可能比HandyJSON更有效,特別是在類型安全和編譯時(shí)檢查方面。
  3. 類型安全性高的場景: Codable提供了更強(qiáng)的類型安全性,這有助于在編譯時(shí)捕捉錯(cuò)誤。在處理嚴(yán)格遵循特定模型的數(shù)據(jù)時(shí),這種類型檢查可能帶來性能優(yōu)勢。
  4. 與Swift特性集成: Codable與Swift的其他特性(如類型推斷、泛型等)集成得更緊密,這可能在某些情況下提高解析效率。

然而,這些差異并不是絕對的。HandyJSON在某些情況下(如處理動(dòng)態(tài)或非結(jié)構(gòu)化的JSON數(shù)據(jù))可能表現(xiàn)得更好。性能也會(huì)受到JSON數(shù)據(jù)的大小和復(fù)雜性、應(yīng)用的具體實(shí)現(xiàn)方式以及運(yùn)行時(shí)環(huán)境等因素的影響。實(shí)際應(yīng)用中,選擇CodableHandyJSON應(yīng)基于具體的項(xiàng)目需求和上下文。

如何使用SmartCodable?

使用SmartCodable與使用標(biāo)準(zhǔn)的Codable類似,但你會(huì)獲得額外的錯(cuò)誤處理能力和更加靈活的解析選項(xiàng)。只需將你的數(shù)據(jù)模型遵循SmartCodable協(xié)議,即可開始享受更加智能的數(shù)據(jù)解析體驗(yàn)。

cocopods集成

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0'
use_frameworks!

target 'MyApp' do
  pod 'SmartCodable'
end

字典類型的解碼

import SmartCodable

struct Model: SmartCodable {
    var name: String = ""
}

let dict: [String: String] = ["name": "xiaoming"]
guard let model = Model.deserialize(dict: dict) else { return }

數(shù)組類型解碼

import SmartCodable

struct Model: SmartCodable {
    var name: String = ""
}

let dict: [String: String] = ["name": "xiaoming"]
let arr = [dict, dict]
guard let models = [Model].deserialize(array: arr) else { return }

序列化與反序列化

// 字典轉(zhuǎn)模型
guard let xiaoMing = JsonToModel.deserialize(dict: dict) else { return }

// 模型轉(zhuǎn)字典
let studentDict = xiaoMing.toDictionary() ?? [:]

// 模型轉(zhuǎn)json字符串
let json1 = xiaoMing.toJSONString(prettyPrint: true) ?? ""

// json字符串轉(zhuǎn)模型
guard let xiaoMing2 = JsonToModel.deserialize(json: json1) else { return }

解析完成的回調(diào)

class Model: SmartDecodable {

    var name: String = ""
    var age: Int = 0
    var desc: String = ""
    required init() { }
    
    // 解析完成的回調(diào)
    func didFinishMapping() {    
        if name.isEmpty {
            desc = "\(age)歲的" + "人"
        } else {
            desc = "\(age)歲的" + name
        }
    }
}

枚舉的解碼

struct CompatibleEnum: SmartCodable {

    init() { }
    var enumTest: TestEnum = .a

    enum TestEnum: String, SmartCaseDefaultable {
        static var defaultCase: TestEnum = .a

        case a
        case b
        case hello = "c"
    }
}

讓你的枚舉遵守 SmartCaseDefaultable 協(xié)議,如果枚舉解析失敗,將使用defaultCase作為默認(rèn)值。

解碼Any

Codable是無法解碼Any類型的,這樣就意味著模型的屬性類型可以為 Any,[Any][String: Any]。 這對解碼的便利性造成了一定的困擾。

官方的解決方案

對非原生類型字段,給它再生成一個(gè)struct,用原生類型來表述屬性就行。

struct Block: Codable {
    let message: String
    let index: Int
    let transactions: [[String: Any]]
    let proof: String
    let previous_hash: String
}

改為:

struct Transaction: Codable {
    let amount: Int
    let recipient: String
    let sender: String
}
 
struct Block: Codable {
    let message: String
    let index: Int
    let transactions: [Transaction]
    let proof: String
    let previous_hash: String
}

使用泛型

如果情況允許,可以使用泛型來代替。

struct AboutAny<T: Codable>: SmartCodable {
    init() { }

    var dict1: [String: T] = [:]
    var dict2: [String: T] = [:]
}
guard let one = AboutAny<String>.deserialize(dict: dict) else { return }

使用 SmartAny

SmartAnySmartCodable 提供了一種方案。SmartAny是枚舉類型。

public enum SmartAny {
    case bool(Bool)
    case string(String)
    case double(Double)
    case cgFloat(CGFloat)
    case float(Float)
    case int(Int)
    case int8(Int8)
    case int16(Int16)
    case int32(Int32)
    case int64(Int64)
    case uInt(Int)
    case uInt8(UInt8)
    case uInt16(UInt16)
    case uInt32(UInt32)
    case uInt64(UInt64)    
    case dict([String: SmartAny])
    case array([SmartAny])
}

重寫了public init(from decoder: Decoder) throws方法,將解析完成的數(shù)據(jù)包裹進(jìn)SmartAny內(nèi)。

extension SmartAny: Codable {
    // 實(shí)現(xiàn) Codable
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        
        
        if let value = try? container.decode(Bool.self) {
            self = .bool(value)
        } else if let value = try? container.decode(String.self) {
            self = .string(value)
        }
        其他代碼
        ......
    }
}

如果你要獲取原始的數(shù)據(jù),可以使用 peel 方法去殼。

extension Dictionary where Key == String, Value == SmartAny {
    /// 解析完成會(huì)被SmartAny包裹,使用該屬性去殼。
    public var peel: [String: Any] {
        var temp: [String: Any] = [:]
        for (key, value) in self {
            temp.updateValue(value.peel, forKey: key)
        }
        return temp
    }
}

extension Array where Element == SmartAny {
    /// 解析完成會(huì)被SmartAny包裹,使用該屬性去殼。
    public var peel: [Any] {
        var temp: [Any] = []
        
        temp = self.map({
            $0.peel
        })
        return temp
    }
}

extension SmartAny {
    /// 獲取原本的值
    public var peel: Any {
        switch self {
        case .bool(let v):
            return v
            
        case .string(let v):
            return v
        
        // 其他代碼
        ......
        }
    }
}

更多實(shí)現(xiàn)細(xì)節(jié)可以訪問SmartAny.swift 文件。

解碼策略 - SmartDecodingOption

public static func deserialize(json: String?, options: [SmartDecodingOption]? = nil) -> Self? 

options提供了四種解碼選項(xiàng),分別為:

    /// 用于在解碼之前自動(dòng)更改密鑰值的策略
    case keyStrategy(KeyDecodingStrategy)
    
    /// 用于解碼 “Date” 值的策略
    case dateStrategy(JSONDecoder.DateDecodingStrategy)
    
    /// 用于解碼 “Data” 值的策略
    case dataStrategy(JSONDecoder.DataDecodingStrategy)
    
    /// 用于不符合json的浮點(diǎn)值(IEEE 754無窮大和NaN)的策略
    case floatStrategy(JSONDecoder.NonConformingFloatDecodingStrategy)

SmartKeyDecodingStrategy

/// key解碼策略
public enum SmartKeyDecodingStrategy {
    case useDefaultKeys
    case convertFromSnakeCase
    case custom([String: String])
}
  • useDefaultKeys: 使用默認(rèn)的解析映射方式。

  • convertFromSnakeCase: 轉(zhuǎn)駝峰的命名方式。會(huì)將本次解析的字段,全部轉(zhuǎn)成駝峰命名。

  • custom: 自定義的方式。key是數(shù)據(jù)中的字段名,value是模型中的屬性名。

// 1. CodingKeys 映射
guard let feedOne = FeedOne.deserialize(json: json) else { return }

// 2.  使用keyDecodingStrategy的駝峰命名
guard let feedTwo = FeedTwo.deserialize(json: json, options: [.keyStrategy(.convertFromSnakeCase)]) else { return }



// 3. 使用keyDecodingStrategy的自定義策略
let option: SmartDecodingOption = .keyStrategy(.custom(["nick_name": "name"]))
guard let feedThree = FeedThree.deserialize(json: json, options: [option]) else { return }

Date格式的解碼

let json = """
{
   "birth": "2034-12-01 18:00:00"
}
"""
let dateFormatter = DateFormatter()
 dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let option: SmartDecodingOption = .dateStrategy(.formatted(dateFormatter))

guard let model = FeedOne.deserialize(json: json, options: [option]) else { return }

Data類型的解碼

let json = """
{
   "address": "aHR0cHM6Ly93d3cucWl4aW4uY29t"
}
"""

let option: SmartDecodingOption = .dataStrategy(.base64)
guard let model = FeedOne.deserialize(json: json, options: [option]) else { return }

if let data = model.address, let url = String(data: data, encoding: .utf8) {
    print(url)
    // https://www.qixin.com
}

SmartCodable的兼容性

在使用系統(tǒng)的 Codable 解碼的時(shí)候,遇到 無鍵,值為null值類型錯(cuò)誤 拋出異常導(dǎo)致解析失敗。SmartCodable 底層默認(rèn)對這三種解析錯(cuò)誤進(jìn)行了兼容。

具體的實(shí)現(xiàn)邏輯可以查看 Patcher.swift 文件。

無鍵 & 值為null

這兩種情況的數(shù)據(jù),我稱之為擺爛數(shù)據(jù),這種數(shù)據(jù)無法拯救。

解析到 無鍵 & 值為null 的時(shí)候,SmartCodable會(huì)提供該字段類型的默認(rèn)值進(jìn)行解析填充(如果是可選類型,提供nil)。使解析順利進(jìn)行。

對這兩份數(shù)據(jù),解析到 CompatibleTypes 模型中

var json: String {
   """
   {
   }
   """
}
var json: String {
   """
   {
     "a": null,
     "b": null,
     "c": null,
     "d": null,
     "e": null,
     "f": null,
     "g": null,
     "h": null,
     "i": null,
     "j": null,
     "k": null,
     "l": null,

     "v": null,
     "w": null,
     "x": null,
     "y": null,
     "z": null
   }
   """
}
struct CompatibleTypes: SmartDecodable {

    var a: String = ""
    var b: Bool = false
    var c: Date = Date()
    var d: Data = Data()

    var e: Double = 0.0
    var f: Float = 0.0
    var g: CGFloat = 0.0

    var h: Int = 0
    var i: Int8 = 0
    var j: Int16 = 0
    var k: Int32 = 0
    var l: Int64 = 0

    var m: UInt = 0
    var n: UInt8 = 0
    var o: UInt16 = 0
    var p: UInt32 = 0
    var q: UInt64 = 0

    var v: [String] = []
    var w: [String: [String: Int]] = [:]
    var x: [String: String] = [:]
    var y: [String: Int] = [:]
    var z: CompatibleItem = CompatibleItem()
}

class CompatibleItem: SmartDecodable {
    var name: String = ""
    var age: Int = 0   
    required init() { }
}

解析完成后,將使用該屬性對應(yīng)的數(shù)據(jù)類型的默認(rèn)值進(jìn)行填充。

guard let person = CompatibleTypes.deserialize(json: json) else { return }
/**
 "屬性:a 的類型是 String, 其值為 "
 "屬性:b 的類型是 Bool, 其值為 false"
 "屬性:c 的類型是 Date, 其值為 2001-01-01 00:00:00 +0000"
 "屬性:d 的類型是 Data, 其值為 0 bytes"
 "屬性:e 的類型是 Double, 其值為 0.0"
 "屬性:f 的類型是 Float, 其值為 0.0"
 "屬性:g 的類型是 CGFloat, 其值為 0.0"
 "屬性:h 的類型是 Int, 其值為 0"
 "屬性:i 的類型是 Int8, 其值為 0"
 "屬性:j 的類型是 Int16, 其值為 0"
 "屬性:k 的類型是 Int32, 其值為 0"
 "屬性:l 的類型是 Int64, 其值為 0"
 "屬性:m 的類型是 UInt, 其值為 0"
 "屬性:n 的類型是 UInt8, 其值為 0"
 "屬性:o 的類型是 UInt16, 其值為 0"
 "屬性:p 的類型是 UInt32, 其值為 0"
 "屬性:q 的類型是 UInt64, 其值為 0"
 "屬性:v 的類型是 Array<String>, 其值為 []"
 "屬性:w 的類型是 Dictionary<String, Dictionary<String, Int>>, 其值為 [:]"
 "屬性:x 的類型是 Dictionary<String, String>, 其值為 [:]"
 "屬性:y 的類型是 Dictionary<String, Int>, 其值為 [:]"
 "屬性:z 的類型是 CompatibleItem, 其值為 CompatibleItem(name: \"\", age: 0)"
 */

值類型錯(cuò)誤

這種情況的數(shù)據(jù),我稱之為可拯救的數(shù)據(jù)。例如: Model中定義的Bool類型,數(shù)據(jù)中返回的是Int類型的0或1,String類型的True/true/Yes/No等。

解析到 值類型錯(cuò)誤 的時(shí)候,SmartCodable會(huì)嘗試對數(shù)據(jù)值進(jìn)行類型轉(zhuǎn)換,如果轉(zhuǎn)換成功,將使用該值。如果轉(zhuǎn)換失敗,將使用該屬性對應(yīng)的數(shù)據(jù)類型的默認(rèn)值進(jìn)行填充。

Bool類型的轉(zhuǎn)換

/// 兼容Bool類型的值,Model中定義為Bool類型,但是數(shù)據(jù)中是String,Int的情況。
static func compatibleBoolType(value: Any) -> Bool? {
    switch value {
    case let intValue as Int:
        if intValue == 1 {
            return true
        } else if intValue == 0 {
            return false
        } else {
             return nil
        }
    case let stringValue as String:
        switch stringValue {
        case "1", "YES", "Yes", "yes", "TRUE", "True", "true":
            return true
        case "0",  "NO", "No", "no", "FALSE", "False", "false":
            return false
        default:
            return nil
        }
    default:
        return nil
    }
}

String類型的轉(zhuǎn)換

/// 兼容String類型的值
static func compatibleStringType(value: Any) -> String? {
    
    switch value {
    case let intValue as Int:
        let string = String(intValue)
        return string
    case let floatValue as Float:
        let string = String(floatValue)
        return string
    case let doubleValue as Double:
        let string = String(doubleValue)
        return string
    default:
        return nil
    }
}

其他更多類型

請查看 TypePatcher.swift 了解更多。

調(diào)試日志

SmartCodable鼓勵(lì)從根本上解決解析中的問題,即:不需要用到SmartCodable的兼容邏輯。 如果出現(xiàn)解析兼容的情況,修改Model中屬性的定義,或要求數(shù)據(jù)方進(jìn)行修正。為了更方便的定位問題,SmartCodable提供了便捷的解析錯(cuò)誤日志。

調(diào)試日志,將提供輔助信息,幫助定位問題:

  • 錯(cuò)誤類型: 錯(cuò)誤的類型信息
  • 模型名稱:發(fā)生錯(cuò)誤的模型名出
  • 數(shù)據(jù)節(jié)點(diǎn):發(fā)生錯(cuò)誤時(shí),數(shù)據(jù)的解碼路徑。
  • 屬性信息:發(fā)生錯(cuò)誤的字段名。
  • 錯(cuò)誤原因: 錯(cuò)誤的具體原因。
================ [SmartLog Error] ================
錯(cuò)誤類型: '找不到鍵的錯(cuò)誤' 
模型名稱:Array<Class> 
數(shù)據(jù)節(jié)點(diǎn):Index 0 → students → Index 0
屬性信息:(名稱)more
錯(cuò)誤原因: No value associated with key CodingKeys(stringValue: "more", intValue: nil) ("more").
==================================================

================ [SmartLog Error] ================
錯(cuò)誤類型: '值類型不匹配的錯(cuò)誤' 
模型名稱:DecodeErrorPrint 
數(shù)據(jù)節(jié)點(diǎn):a
屬性信息:(類型)Bool (名稱)a
錯(cuò)誤原因: Expected to decode Bool but found a string/data instead.
==================================================


================ [SmartLog Error] ================
錯(cuò)誤類型: '找不到值的錯(cuò)誤' 
模型名稱:DecodeErrorPrint 
數(shù)據(jù)節(jié)點(diǎn):c
屬性信息:(類型)Bool (名稱)c
錯(cuò)誤原因:  c 在json中對應(yīng)的值是null
==================================================

你可以通過SmartConfig 調(diào)整日志的相關(guān)設(shè)置。

如何理解數(shù)據(jù)節(jié)點(diǎn)?
image.png

右側(cè)的數(shù)據(jù)是數(shù)組類型。注意標(biāo)紅的內(nèi)容,由外到里對照查看。

  • Index 0: 數(shù)組的下標(biāo)為0的元素。

  • sampleFive: 下標(biāo)為0的元素對應(yīng)的是字典,即字典key為sampleFive對應(yīng)的值(是一個(gè)數(shù)組)。

  • Index 1:數(shù)組的下標(biāo)為1的元素.

  • sampleOne:字典中key為sampleOne對應(yīng)的值。

  • string:字典中key為sring對應(yīng)的值。

四. SamrtCodable的缺點(diǎn)

1. 可選模型屬性

struct Feed: SmartCodable {
    var one: FeedOne?
}
struct FeedOne: SmartCodable {
    var name: String = ""
}

如有模型中的屬性是嵌套的模型屬性,遇到類型不匹配的情況,Codable無法解析拋出異常,這種情況的異常,SmartCodale將無法兼容。

此時(shí)您有兩種選擇:

  • 將Feed中one這個(gè)屬性設(shè)置為非可選的。 SmartCodable 將正常工作。
  • 將該屬性使用 @SmartOptional 屬性包裝器修飾。
struct Feed: SmartCodable {
    @SmartOptional var one: FeedOne?
}

class FeedOne: SmartCodable {
    var name: String = ""
    required init() { }
}

這是一個(gè)不得已的實(shí)現(xiàn)方案:

為了做解碼失敗的兼容,我們重寫了 KeyedEncodingContainerdecodedecodeIfPresent 方法。

需要注意的是:decodeIfPresent底層的實(shí)現(xiàn)仍是使用的 decode。

// 系統(tǒng)Codable源碼實(shí)現(xiàn)
public extension KeyedDecodingContainerProtocol {
    @_inlineable // FIXME(sil-serialize-all)
    public func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
        guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }

        return try self.decode(Bool.self, forKey: key)
    }
}

KeyedEncodingContainer容器是用結(jié)構(gòu)體實(shí)現(xiàn)的。 重寫了結(jié)構(gòu)體的方法之后,沒辦法再調(diào)用父方法。

  1. 這種情況下,如果再重寫 public func decodeIfPresent<T>(_ type: T.Type, forKey key: K) throws -> T? 方法,就會(huì)導(dǎo)致方法的循環(huán)調(diào)用。
  2. 使用SmartOptional屬性包裝器修飾可選屬性,被修飾后會(huì)產(chǎn)生一個(gè)新的類型,對此類型解碼就不會(huì)走decodeIfPresent,而是會(huì)走decode方法。

使用SmartOptional的三個(gè)限制條件

  • 必須遵循SmartDecodable協(xié)議

  • 必須是可選屬性

    如果不是可選屬性,就沒必要使用SmartOptional。

  • 必須是class類型

    如果模型是Struct,是值類型。在執(zhí)行 didFinishMapping 的時(shí)候,無法初始化被屬性包裝器修飾的屬性,進(jìn)而無法有效的執(zhí)行解碼完成之后的值修改。

如果你有更好的方案,可以提issue。

2. 模型中設(shè)置的默認(rèn)值無效

Codable在進(jìn)行解碼的時(shí)候,是無法知道這個(gè)屬性的。所以在decode的時(shí)候,如果解析失敗,使用默認(rèn)值進(jìn)行填充時(shí),拿不到這個(gè)默認(rèn)值。再處理解碼兼容時(shí),只能自己生成一個(gè)對應(yīng)類型的默認(rèn)值填充。

如果你有更好的方案,可以提issue。

進(jìn)一步了解

我們提供了詳細(xì)的示例工程,可以下載工程代碼查看。

image.png

加入我們

SmartCodable 是一個(gè)開源項(xiàng)目,我們歡迎所有對提高數(shù)據(jù)解析性能和健壯性感興趣的開發(fā)者加入。無論是使用反饋、功能建議還是代碼貢獻(xiàn),你的參與都將極大地推動(dòng) SmartCodable 項(xiàng)目的發(fā)展。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容