### New Project Setup - Upgrading to Full Version Source: https://github.com/iammccc/smartcodable/blob/main/PACKAGE_MIGRATION_GUIDE.md How to upgrade a new project to the full SmartCodableWithMacros product if inheritance features are needed. ```swift dependencies: [ .product(name: "SmartCodableWithMacros", package: "SmartCodable") ] ``` -------------------------------- ### Quick Start Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md A basic example demonstrating how to use SmartCodable to deserialize a dictionary into a Swift struct. ```swift import SmartCodable struct User: SmartCodableX { var name: String = "" var age: Int = 0 } let user = User.deserialize(from: ["name": "John", "age": 30]) ``` -------------------------------- ### CocoaPods Installation - Basic Source: https://github.com/iammccc/smartcodable/blob/main/README.md Basic installation of SmartCodable using CocoaPods. ```bash pod 'SmartCodable' ``` -------------------------------- ### Swift Syntax Version Constraint Source: https://github.com/iammccc/smartcodable/blob/main/PACKAGE_MIGRATION_GUIDE.md Example of how to specify the swift-syntax package dependency with a version constraint for better compatibility. ```swift .package(url: "https://github.com/swiftlang/swift-syntax", from: "509.0.0") ``` -------------------------------- ### Decoding Strategies Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Example of setting up decoding options for key, date, and data decoding. ```swift let options: Set = [ .key(.convertFromSnakeCase), .date(.iso8601), .data(.base64) ] ``` -------------------------------- ### Data Decoding Strategy Example Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of using .dataStrategy to decode Data values using Base64. ```swift let option: JSONDecoder.SmartDecodingOption = .dataStrategy(.base64) guard let model = FeedOne.deserialize(from: json, options: [option]) else { return } gurad let data = model.address, let url = String(data: data, encoding: .utf8) { else } ``` -------------------------------- ### Date Decoding Strategy Example Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of using .dateStrategy to decode Date values with a custom formatter. ```swift let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" let option: JSONDecoder.SmartDecodingOption = .dateStrategy(.formatted(dateFormatter)) guard let model = FeedOne.deserialize(from: json, options: [option]) else { return } ``` -------------------------------- ### Decoding Dynamic Data with JSON Examples Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates how to handle dynamic data structures in JSON by providing examples for different travel tools (walk, riding, publicTransport) and their corresponding JSON payloads. ```json { "travelTool": "walk", "walk": { "hours": 3, } } ``` ```json { "travelTool": "riding", "riding": { "hours":2, "attention": "注意带头盔" } } ``` ```json { "travelTool": "publicTransport", "publicTransport": { "hours": 1, "transferTimes": "3", } } ``` -------------------------------- ### HandyJSON: Handling inheritance Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of handling inheritance with HandyJSON. ```swift class HandyBaseModel: HandyJSON { var name: String? required init() { } } class HandyModel: HandyBaseModel { var age: Int? } ``` -------------------------------- ### Float Decoding Strategy Example Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of using .floatStrategy to handle non-conforming float values. ```swift let option: JSONDecoder.SmartDecodingOption = .floatStrategy(.convertFromString(positiveInfinity: "infinity", negativeInfinity: "-infinity", nan: "NaN")) guard let model1 = FeedOne.deserialize(from: json, options: [option]) else { return } ``` -------------------------------- ### Update Existing Model Example Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of using SmartUpdater to update an existing SmartCodable model with new data. ```swift struct Model: SmartCodable { var name: String = "" var age: Int = 0 } var dic1: [String : Any] = [ "name": "mccc", "age": 10 ] let dic2: [String : Any] = [ "age": 200 ] guard var model = Model.deserialize(from: dic1) else { return } SmartUpdater.update(&model, from: dic2) // now: model is ["name": mccc, "age": 200]. ``` -------------------------------- ### UnkeyedDecodingContainer Usage Example Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage An example demonstrating how to use UnkeyedDecodingContainer to decode an array of Ints into a Feed struct. ```swift struct Feed: Codable { var value1: Int = 0 var value2: Int = 0 init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() if try container.decodeNil() { value1 = 0 } else { value1 = try container.decode(Int.self) } if try container.decodeNil() { value2 = 0 } else { value2 = try container.decode(Int.self) } } } let json = """ [1, 2] """ guard let feed = json.decode(type: Feed.self) else { return } print(feed) // Feed(value1: 1, value2: 2) 这个数组数据[1, 2], 按照index的顺序逐个解码。 数据 **[1,2]** 和模型属性 **[value1,value2]** 按照顺序一一对应。就形成对应关系 **[1 -> value1]** , **[2 -> value2]** 。 ``` -------------------------------- ### UnkeyedDecodingContainer Error Example Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage An example showing the error that occurs when trying to decode more elements than available in an UnkeyedDecodingContainer. ```swift init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() if try container.decodeNil() { value1 = 0 } else { value1 = try container.decode(Int.self) } if try container.decodeNil() { value2 = 0 } else { value2 = try container.decode(Int.self) } do { try container.decodeNil() } catch { print(error) } } // 报错信息 ▿ DecodingError ▿ valueNotFound : 2 elements - .0 : Swift.Optional ▿ .1 : Context ▿ codingPath : 1 element ▿ 0 : _JSONKey(stringValue: "Index 2", intValue: 2) - stringValue : "Index 2" ▿ intValue : Optional - some : 2 - debugDescription : "Unkeyed container is at end." - underlyingError : nil ``` -------------------------------- ### CocoaPods Installation - Inheritance Source: https://github.com/iammccc/smartcodable/blob/main/README.md Installation of SmartCodable with inheritance support using CocoaPods. ```bash pod 'SmartCodable/Inherit' ``` -------------------------------- ### Serialization Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Examples of serializing a SmartCodable object to a model, dictionary, and JSON string. ```swift // to model guard let xiaoMing = JsonToModel.deserialize(from: dict) else { return } // to dict let studentDict = xiaoMing.toDictionary() ?? [: ] // to json let json1 = xiaoMing.toJSONString(prettyPrint: false) ?? "" ``` -------------------------------- ### Basic Codable Usage Example Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates how to use Codable to decode JSON data into a Swift struct. ```swift struct Feed: Codable { var name: String var id: Int } let dict = [ "id": 2, "name": "小明", ] as [String : Any] let jsonStr = dict.bt_toJSONString() ?? "" guard let jsonData = jsonStr.data(using: .utf8) else { return } let decoder = JSONDecoder() do { let feed = try decoder.decode(Feed.self, from: jsonData) print(feed) } catch let error { print(error) } // Feed(name: "小明", id: 2) ``` -------------------------------- ### Decoding Any Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of using SmartAny to decode Any, [Any], and [String: Any] types. ```swift struct AnyModel: SmartCodable { @SmartAny var name: Any? @SmartAny var dict: [String: Any] = [: ] @SmartAny var arr: [Any] = [] } ``` ```swift let dict = [ "name": "xiao ming", "age": 20, "dict": inDict, "arr": arr ] as [String : Any] guard let model = AnyModel.deserialize(from: dict) else { return } ``` -------------------------------- ### Key Decoding Strategy: Custom Example Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates how to use a custom key decoding strategy to map JSON keys to Swift properties. ```swift do { let decoder = JSONDecoder() /// 默认的 // decoder.keyDecodingStrategy = .useDefaultKeys /// 小驼峰 read_name -> readName // decoder.keyDecodingStrategy = .convertFromSnakeCase /// 自定义 需要返回CodingKey类型。 decoder.keyDecodingStrategy = .custom({ for path in $0 { if path.stringValue == "read_name" { return CustomJSONKey.init(stringValue: "readName")! } else { return path } } return CustomJSONKey.super }) let feed = try decoder.decode(DecodingStrtegyFeed.self, from: jsonData) print(feed) } catch let error { print(error) } ``` -------------------------------- ### HandyJSON: Enum parsing Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of enum parsing with HandyJSON. ```swift enum HandySex: String, HandyJSONEnum { case man case women } struct HandyModel: HandyJSON { var sex: HandySex = .man } ``` -------------------------------- ### HandyJSON: Parsing 'Any' type Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of parsing 'Any' type with HandyJSON. ```swift struct HandyModel: HandyJSON { var name: Any? var dict: [String: Any] = [:] } guard let handyModel = HandyModel.deserialize(from: dict) else { return } print(handyModel.name) print(handyModel.dict) ``` -------------------------------- ### Swift Package Manager Installation Source: https://github.com/iammccc/smartcodable/blob/main/README.md Installation of SmartCodable using Swift Package Manager. ```swift dependencies: [ .package(url: "https://github.com/iAmMccc/SmartCodable.git", from: "xxx") ] ``` -------------------------------- ### Enum Conversion Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Shows how to make an enum convertible by conforming to SmartCaseDefaultable and provides an example of deserializing an enum. ```swift struct Student: SmartCodableX { var name: String = "" var sex: Sex = .man enum Sex: String, SmartCaseDefaultable { case man = "man" case woman = "woman" } } let model = Student.deserialize(from: json) ``` -------------------------------- ### SingleValueDecodingContainer Usage Example Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage An example demonstrating how to use SingleValueDecodingContainer to decode a String value into a Feed struct. ```swift struct Feed: Decodable { let string: String init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() string = try container.decode(String.self) } } let json = """ "Hello, World!" """ guard let feed = json.decode(type: Feed.self) else { return } print(feed) // Feed(string: "Hello, World!") ``` -------------------------------- ### Existing Project Migration - With @SmartSubclass Source: https://github.com/iammccc/smartcodable/blob/main/PACKAGE_MIGRATION_GUIDE.md Guidance for existing projects that use @SmartSubclass, recommending migration to SmartCodableWithMacros. ```swift // Migrate to SmartCodableWithMacros dependencies: [ .product(name: "SmartCodableWithMacros", package: "SmartCodable") ] ``` -------------------------------- ### Decoding Example: Normal JSON Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage A standard example of decoding a JSON string into a Swift Codable struct. ```swift struct Feed: Codable { var name: String } let json = """ { "name": "小明" } """ guard let jsonData = json.data(using: .utf8) else { return } let decoder = JSONDecoder() do { let feed = try decoder.decode(Feed.self, from: jsonData) print(feed) } catch let error { print(error) } ``` -------------------------------- ### HandyJSON: Model with didFinishMapping callback Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of a HandyJSON model implementing the didFinishMapping callback. ```swift struct HandyModel: HandyJSON { var name: String = "" func didFinishMapping() { } } ``` -------------------------------- ### SmartCodable Deserialization Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of deserializing dictionary and array data using SmartCodable. ```swift guard let smartModel = SmartModel.deserialize(from: dict) else { return } guard let smartModels = [SmartModel].deserialize(from: [dict]) else { return } ``` -------------------------------- ### SmartCodable: Model with didFinishMapping callback Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of a SmartCodable model implementing the didFinishMapping callback. ```swift struct SmartModel: SmartCodable { var name: String = "" func didFinishMapping() { } } ``` -------------------------------- ### Deep Path Navigation Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Example of using designatedPath to access nested JSON data. ```swift // JSON Structure: { "data": { "user": { "info": { ...target content... } } } } // Access nested data: Model.deserialize(from: json, designatedPath: "data.user.info") ``` -------------------------------- ### Key Transformation Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Demonstrates how to map JSON keys to model properties using `mappingForKey`. ```swift static func mappingForKey() -> [SmartKeyTransformer]? { return [ CodingKeys.id <--- ["user_id", "userId", "id"], CodingKeys.joinDate <--- "joined_at" ] } ``` -------------------------------- ### Compatibility Example Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Demonstrates how SmartCodable handles compatibility processing for thrown exceptions during attribute resolution, ensuring parsing is not interrupted. ```swift let dict = [ "number1": "123", "number2": "Mccc", "number3": "Mccc" ] struct Model: SmartCodable { var number1: Int? var number2: Int? var number3: Int = 1 } // decode result // Model(number1: 123, number2: nil, number3: 1) ``` -------------------------------- ### HandyJSON Deserialization Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of deserializing dictionary and array data using HandyJSON. ```swift guard let handyModel = HandyModel.deserialize(from: dict) else { return } guard let handyModels = [HandyModel].deserialize(from: [dict]) as? [HandyModel] else { return } ``` -------------------------------- ### Basic Inheritance Support Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Demonstrates basic inheritance support using @SmartSubclass. ```swift class BaseModel: SmartCodableX { var name: String = "" required init() { } } @SmartSubclass class StudentModel: BaseModel { var age: Int? } ``` -------------------------------- ### Decoding UIColor Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of decoding a color string into a SmartColor object. ```swift let dict = [ "color": "7DA5E3" ] struct Model: SmartCodable { var color: SmartColor? } guard let model = Model.deserialize(from: dict) else { return } print(model.color?.peel) ``` -------------------------------- ### didFinishMapping Callback Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of overriding didFinishMapping to perform actions after decoding is complete. ```swift class Model: SmartDecodable { var name: String = "" var age: Int = 0 var desc: String = "" required init() { } func didFinishMapping() { if name.isEmpty { name = "-" } } } ``` -------------------------------- ### Migration Scenario 2: Using @SmartSubclass (Recommended) Source: https://github.com/iammccc/smartcodable/blob/main/PACKAGE_MIGRATION_GUIDE.md For projects using @SmartSubclass, the recommended migration is to switch to the 'SmartCodableWithMacros' product in Package.swift. ```swift // Recommended: dependencies: [ .product(name: "SmartCodableWithMacros", package: "SmartCodable") ] ``` -------------------------------- ### SmartAny reflection Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example showing how SmartAny might affect reflection due to its property wrapper nature. ```swift let e = Mirror(reflecting: self).children for item in e { print(item.label) } ``` -------------------------------- ### SmartCodable Class Model Declaration Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of declaring a class-based model using SmartCodable. ```swift import SmartCodable class SmartModel: SmartCodable { var name: String = "" required init() { } } ``` -------------------------------- ### SmartCodable: Parsing 'Any' type with SmartAny Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of parsing 'Any' type with SmartCodable using the @SmartAny wrapper. ```swift struct SmartModel: SmartCodable { @SmartAny var name: Any? @SmartAny var dict: [String: Any] = [:] } guard let smartModel = SmartModel.deserialize(from: dict) else { return } print(smartModel.name) print(smartModel.dict) ``` -------------------------------- ### SmartCodable Struct Model Declaration Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of declaring a struct-based model using SmartCodable. ```swift import SmartCodable struct SmartModel: SmartCodable { var name: String = "" } ``` -------------------------------- ### SmartCodable: Handling inheritance with @SmartSubclass Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of handling inheritance with SmartCodable using the @SmartSubclass annotation. ```swift class BaseModel: SmartCoable { var name: String? required init() { } } @SmartSubclass class HandyModel: BaseModel { var age: Int? } ``` -------------------------------- ### SmartCodable: Enum parsing with SmartCaseDefaultable Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of enum parsing with SmartCodable using the SmartCaseDefaultable protocol. ```swift enum SmartSex: String, SmartCaseDefaultable { case man case women } struct SmartModel: SmartCodable { var sex: SmartSex = .man } ``` -------------------------------- ### SmartHexColor Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Demonstrates using the @SmartHexColor property wrapper for UIColor/NSColor with Codable. ```swift struct Model: SmartCodableX { @SmartHexColor var color: UIColor? } let dict: [String: Any] = [ "color": "7DA5E3" ] let model = Model.deserialize(from: dict) print(model) // print: Model(color: UIExtendedSRGBColorSpace 0.490196 0.647059 0.890196 1) ``` -------------------------------- ### Sentinel Log Output Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/Sentinel.md Example of the formatted log information displayed by Smart Sentinel after parsing is complete. ```text ================================ [Smart Sentinel] ================================ Array 👈🏻 👀 ╆━ Index 0 ┆┄ a: Expected to decode 'Int' but found ‘String’ instead. ┆┄ b: Expected to decode 'Int' but found ’Array‘ instead. ┆┄ c: No value associated with key. ╆━ sub: SubModel ┆┄ sub_a: No value associated with key. ┆┄ sub_b: No value associated with key. ┆┄ sub_c: No value associated with key. ╆━ sub2s: [SubTwoModel] ╆━ Index 0 ┆┄ sub2_a: No value associated with key. ┆┄ sub2_b: No value associated with key. ┆┄ sub2_c: No value associated with key. ╆━ Index 1 ┆┄ sub2_a: Expected to decode 'Int' but found ’Array‘ instead. ╆━ Index 1 ┆┄ a: No value associated with key. ┆┄ b: Expected to decode 'Int' but found ‘String’ instead. ┆┄ c: Expected to decode 'Int' but found ’Array‘ instead. ╆━ sub: SubModel ┆┄ sub_a: Expected to decode 'Int' but found ‘String’ instead. ╆━ sub2s: [SubTwoModel] ╆━ Index 0 ┆┄ sub2_a: Expected to decode 'Int' but found ‘String’ instead. ╆━ Index 1 ┆┄ sub2_a: Expected to decode 'Int' but found 'null' instead. ==================================================================================== ``` -------------------------------- ### HandyJSON Class Model Declaration Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of declaring a class-based model using HandyJSON. ```swift import HandyJSON class HandyModel: HandyJSON { var name: String = "" required init() { } } ``` -------------------------------- ### Existing Project Migration - No @SmartSubclass Source: https://github.com/iammccc/smartcodable/blob/main/PACKAGE_MIGRATION_GUIDE.md Guidance for existing projects that do not use @SmartSubclass, recommending they continue using SmartCodable for performance benefits. ```swift // Continue using SmartCodable dependencies: [ .product(name: "SmartCodable", package: "SmartCodable") ] ``` -------------------------------- ### SmartCodable: Custom key mapping and ignoring keys Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of custom key mapping and ignoring keys in SmartCodable using CodingKeys and mappingForKey(). ```swift struct SmartModel: SmartCodable { var name: String = "" var age: Int? var ignoreKey: String = "忽略的key" enum CodingKeys: CodingKey { case name case age // case ignoreKey } static func mappingForKey() -> [SmartKeyTransformer]? { [ CodingKeys.name <--- ["nick_name", "realName"], CodingKeys.age <--- "self_age" ] } } ``` -------------------------------- ### SmartCompact Array and Dictionary Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Illustrates @SmartCompact.Array and @SmartCompact.Dictionary for tolerant decoding of arrays and dictionaries. ```swift struct Model: Decodable { // Array may contain invalid values, those will be ignored @SmartCompact.Array var ages: [Int] // Dictionary may contain invalid entries, those will be ignored @SmartCompact.Dictionary var info: [String: String] } let dict: [String: Any] = [ "ages": ["Tom", 1, [:], 2, 3, "4"], "info": [ "name": "Tom", "age": 18, "extra": [: ] ] ] let model = try! JSONDecoder().decode(Model.self, from: JSONSerialization.data(withJSONObject: dict)) print(model) // print: Model(ages: [1, 2, 3, 4], info: ["name": "Tom", "age": "18"]) ``` -------------------------------- ### Value Transformation Example with Built-in Transformers Source: https://github.com/iammccc/smartcodable/blob/main/README.md Illustrates using `mappingForValue` with various built-in value transformers for dates and URLs. ```swift struct Model: SmartCodableX { ... static func mappingForValue() -> [SmartValueTransformer]? { let format = DateFormatter() format.dateFormat = "yyyy-MM-dd" return [ CodingKeys.url <--- SmartURLTransformer(prefix: "https://"), CodingKeys.date2 <--- SmartDateTransformer(), CodingKeys.date1 <--- SmartDateFormatTransformer(format) ] } } ``` -------------------------------- ### Subclass Implements Protocol Method Example Source: https://github.com/iammccc/smartcodable/blob/main/README.md Shows how a subclass can implement protocol methods like mappingForKey. ```swift class BaseModel: SmartCodableX { var name: String = "" required init() { } class func mappingForKey() -> [SmartKeyTransformer]? { retrun nil } } @SmartSubclass class StudentModel: BaseModel { var age: Int? override static func mappingForKey() -> [SmartKeyTransformer]? { [ CodingKeys.age <--- "stu_age" ] } } ``` -------------------------------- ### User struct with CodingKeys Source: https://github.com/iammccc/smartcodable/blob/main/Document/QA/QA1.md Example of a Swift struct conforming to Decodable and Encodable, with an explicit enum for CodingKeys. ```swift struct User : Decodable & Encodable { @_hasStorage var name: String { get set } @_hasStorage @_hasInitialValue var email: String? { get set } private enum CodingKeys : String, CodingKey { case name init?(rawValue: String) init?(stringValue: String) init?(intValue: Int) typealias RawValue = String var intValue: Int? { get } var rawValue: String { get } var stringValue: String { get } } func encode(to encoder: Encoder) throws init(from decoder: Decoder) throws init(name: String, email: String? = nil) } ``` -------------------------------- ### SIL for User.init(from:) Source: https://github.com/iammccc/smartcodable/blob/main/Document/QA/QA1.md The Swift Intermediate Language (SIL) representation for the User.init(from:) method, showing how properties are extracted and decoded using KeyedDecodingContainer. ```sil // User.init(from:) sil hidden @$s18TestViewController4UserV4fromACs7Decoder_p_tKcfC : $@convention(method) (@in Decoder, @thin User.Type) -> (@owned User, @error Error) { // %0 "decoder" // users: %51, %36, %10, %3 // %1 "$metatype" bb0(%0 : $*Decoder, %1 : $@thin User.Type): %2 = alloc_stack [lexical] $User, var, name "self", implicit // users: %25, %5, %37, %52, %54, %38 debug_value %0 : $*Decoder, let, name "decoder", argno 1, implicit, expr op_deref // id: %3 debug_value undef : $Error, var, name "$error", argno 2 // id: %4 %5 = struct_element_addr %2 : $*User, #User.email // user: %8 %6 = enum $Optional, #Optional.none!enumelt // users: %45, %41, %34, %32, %8, %7 retain_value %6 : $Optional // id: %7 store %6 to %5 : $*Optional // id: %8 %9 = alloc_stack [lexical] $KeyedDecodingContainer, let, name "container", implicit // users: %31, %30, %22, %48, %47, %14, %42 %10 = open_existential_addr immutable_access %0 : $*Decoder to $*@opened("E27EBBFE-E68A-11EE-A740-1EFE426E258A") Decoder // users: %14, %14, %13 %11 = metatype $@thin User.CodingKeys.Type %12 = metatype $@thick User.CodingKeys.Type // user: %14 %13 = witness_method $@opened("E27EBBFE-E68A-11EE-A740-1EFE426E258A") Decoder, #Decoder.container : (Self) -> (Key.Type) throws -> KeyedDecodingContainer, %10 : $*@opened("E27EBBFE-E68A-11EE-A740-1EFE426E258A") Decoder : $@convention(witness_method: Decoder) <τ_0_0 where τ_0_0 : Decoder><τ_1_0 where τ_1_0 : CodingKey> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> (@out KeyedDecodingContainer<τ_1_0>, @error Error) // type-defs: %10; user: %14 try_apply %13<@opened("E27EBBFE-E68A-11EE-A740-1EFE426E258A") Decoder, User.CodingKeys>(%9, %12, %10) : $@convention(witness_method: Decoder) <τ_0_0 where τ_0_0 : Decoder><τ_1_0 where τ_1_0 : CodingKey> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> (@out KeyedDecodingContainer<τ_1_0>, @error Error), normal bb1, error bb3 // type-defs: %10; id: %14 ``` -------------------------------- ### Solution 4: Implementation based on Protocol + @SmartFlat Source: https://github.com/iammccc/smartcodable/blob/main/Document/QA/QA2.md Combines the advantages of both Protocol and @SmartFlat approaches, mitigating their respective shortcomings, offering greater flexibility. ```swift protocol ManBaseModelProtocol { var manBase: BaseModel { set get } } class BaseModel: SmartCodable { required init() {} var name: String = "" var sex: Int = 0 } class SubModel: SmartCodable, ManBaseModelProtocol { required init() {} @SmartFlat var manBase: BaseModel = .init() var age: Int = 0 } ``` -------------------------------- ### Using userInfo for Custom Decoding Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates how to pass custom context information (like language and version) to the decoder via the userInfo property. ```swift struct Feed: Codable { let name: String let age: Int init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .name) self.age = try container.decode(Int.self, forKey: .age) // 从userInfo中获取上下文信息 if let language = decoder.userInfo[.init(rawValue: "language")!] as? String, let version = decoder.userInfo[.init(rawValue: "version")!] as? Double { print("Decoded using (language) (version)") // Decoded using Swift 5.0 } } } let jsonData = """{ "name": "John Doe", "age": 30 }""".data(using: .utf8)! let decoder = JSONDecoder() // 设置userInfo属性,传递自定义的上下文信息 let userInfo: [CodingUserInfoKey: Any] = [ .init(rawValue: "language")!: "Swift", .init(rawValue: "version")!: 5.0] decoder.userInfo = userInfo guard let feed = try? decoder.decode(Feed.self, from: jsonData) else { return } print(feed) ``` -------------------------------- ### Migration Scenario 2: Using @SmartSubclass (Backward Compatible) Source: https://github.com/iammccc/smartcodable/blob/main/PACKAGE_MIGRATION_GUIDE.md An alternative for projects using @SmartSubclass is to keep the existing dependencies, which will continue to work but is not the recommended path. ```swift // Backward compatible: dependencies: [ .product(name: "SmartCodable", package: "SmartCodable"), .product(name: "SmartCodableInherit", package: "SmartCodable") ] ``` -------------------------------- ### Custom init(from decoder: Decoder) for Inheritance Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Overriding init(from decoder: Decoder) to manually handle parsing for inheritance. ```swift class BaseModel: SmartCodable { var name: String = "" var age: Int = 0 enum CodingKeys: CodingKey { case name case age } required init() { } } class SubModel: BaseModel { var nickName: String = "" enum CodingKeys: CodingKey { case nickName } required init(from decoder: Decoder) throws { try super.init(from: decoder) let container = try decoder.container(keyedBy: CodingKeys.self) self.nickName = try container.decode(String.self, forKey: .nickName) } required init() { super.init() } } ``` -------------------------------- ### Decoding enum Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of decoding an enum that conforms to SmartCaseDefaultable. ```swift struct Model: SmartCodable { var enum: MyEnum? } enum myEnum: String, SmartCaseDefaultable { case a case b case c = "hello" } ``` -------------------------------- ### Class Encoding Example without Overrides Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Illustrates the default encoding behavior of a 'Class' struct when no custom encode method is implemented, showing how all properties are encoded directly. ```swift struct Student: Encodable { var name: String enum CodingKeys: CodingKey { case name } } struct Class: Encodable { var numer: Int var monitor: Student var students: [Student] init(numer: Int, monitor: Student, students: [Student]) { self.numer = numer self.monitor = monitor self.students = students } } let monitor = Student(name: "小明") let student1 = Student(name: "大黄") let student2 = Student(name: "小李") var classFeed = Class(numer: 10, monitor: monitor, students: [student1, student2]) guard let value = classFeed.encode() else { return } print(value) // 输出信息是: { "numer" : 10, "monitor" : { "name" : "小明" }, "students" : [ { "name" : "大黄" }, { "name" : "小李" } ] } ``` -------------------------------- ### Decoding dictionary Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of decoding a dictionary into a SmartCodable struct. ```swift import SmartCodable struct Model: SmartCodable { var name: String = "" } let dict: [String: String] = ["name": "xiaoming"] guard let model = Model.deserialize(from: dict) else { return } ``` -------------------------------- ### Compatible Decoding Implementation Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Provides a custom init(from:) implementation to handle missing keys, null values, and type mismatches gracefully. ```swift struct Feed: Codable { var name: String var id: Int init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 1.数据中是否否包含该键 if container.contains(.name) { // 2.是否为nil if try container.decodeNil(forKey: .name) { self.name = "" } else { do { // 3.是否类型正确 self.name = try container.decode(String.self, forKey: .name) } catch { self.name = "" } } } else { self.name = "" } } } ``` -------------------------------- ### Custom Key Mapping with mappingForKey Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Demonstrates how to define custom key mappings for decoding by overriding the mappingForKey static function. ```swift struct Model: SmartCodable { var name: String = "" var age: Int = 0 static func mappingForKey() -> [SmartKeyTransformer]? { [ CodingKeys.age <--- "person_age" CodingKeys.name <--- ["nickName", "realName"], ] } } ``` -------------------------------- ### Decode array Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of decoding an array of dictionaries into an array of SmartCodable structs. ```swift import SmartCodable struct Model: SmartCodable { var name: String = "" } let dict: [String: String] = ["name": "xiaoming"] let arr = [dict, dict] guard let models = [Model].deserialize(from: arr) else { return } ``` -------------------------------- ### Overriding mappingForValue Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of overriding mappingForValue to provide custom parsing policies for attributes. ```swift struct SmartModel: SmartCodable { var date1: Date? var date2: Date? var url: URL? var data: Data? static func mappingForValue() -> [SmartValueTransformer]? { let format = DateFormatter() format.dateFormat = "yyyy-MM-dd" return [ CodingKeys.url <--- SmartURLTransformer(prefix: "https://"), CodingKeys.date2 <--- SmartDateTransformer(), CodingKeys.date1 <--- SmartDateFormatTransformer(format), CodingKeys.data <--- SmartDataTransformer() ] } } ``` -------------------------------- ### Incorrect use of SmartAny Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md An example demonstrating the incorrect usage of SmartAny with generic types. ```swift // ❌ 错误的示范 struct Model: SmartCodable { @SmartAny var data: T? } struct SubModel: SmartCodable { var name: String? } ``` -------------------------------- ### designatedPath (specified path) Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of deserializing from a designated path within a JSON string. ```swift let jsonString = """ { "people": [ { "name": "John Doe", "age": 30 }, { "name": "Jane Smith", "age": 25 } ] } """ struct PathModel: SmartCodable { var name: String? var age: Int? } if let models = [PathModel].deserialize(from: jsonString, designatedPath: "people") { print(models) } ``` -------------------------------- ### Get Generated Logs Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/Sentinel.md Callback function to retrieve generated logs for server upload. ```swift SmartSentinel.onLogGenerated { logs in } ``` -------------------------------- ### Example JSON Structure Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage A complex JSON structure that needs to be flattened for parsing. ```json let res = """ { "player_name": "balabala Team", "age": 20, "native_Place": "shandong", "scoreInfo": { "gross_score": 2.4, "scores": [ 0.9, 0.8, 0.7 ], "remarks": { "judgeOne": { "content": "good" }, "judgeTwo": { "content": "very good" }, "judgeThree": { "content": "bad" } } } } "" ``` -------------------------------- ### Basic Encoding Example Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates a basic encoding scenario where a subclass does not override the parent's encode method, resulting in only parent properties being encoded. ```swift guard let value = point.encode() else { return } print(value) 此时的打印结果是: { "x" : 1, "y" : 2 } 相信你已经反应过来了:子类没有重写父类的 **encode** 方法,默认使用的父类的 **encode** 方法。子类的属性自然没有被 **encode**。 ``` -------------------------------- ### Deserialization API - Data Input Source: https://github.com/iammccc/smartcodable/blob/main/README.md Example of deserializing from Data. ```swift public static func deserialize(from data: Data?, designatedPath: String? = nil, options: Set? = nil) -> Self? ``` -------------------------------- ### Date Formatting for Decoding Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates how to configure `JSONDecoder` with a `DateFormatter` to parse dates in a specific string format. ```swift let json = """ { "birth": "2000-01-01 00:00:01" } """ guard let data = json.data(using: .utf8) else { return } let decoder = JSONDecoder() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" decoder.dateDecodingStrategy = .formatted(dateFormatter) do { let feed = try decoder.decode(Person.self, from: data) print(feed) } catch { print("Error decoding: (error)") } struct Person: Codable { var birth: Date } ``` -------------------------------- ### Deserialization API - Dictionary Input Source: https://github.com/iammccc/smartcodable/blob/main/README.md Example of deserializing from a dictionary. ```swift public static func deserialize(from dict: [String: Any]?, designatedPath: String? = nil, options: Set? = nil) -> Self? ``` -------------------------------- ### Populating the Container with Custom Struct CodingKeys Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates populating the encoding container using a custom struct for CodingKeys, encoding 'id' and 'name' with string initializers. ```swift func encode(to encoder: Encoder) throws { // 使用结构体类型的CodingKeys var container = encoder.container(keyedBy: CustomKeys.self) try container.encode(id, forKey: .init(stringValue: "id")!) try container.encode(name, forKey: .init(stringValue: "name")!) } ``` -------------------------------- ### Modeling of json strings Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Example of modeling a JSON string property within a SmartCodable object. ```swift let dict: [String: Any] = [ "hobby": "{\"name\":\"sleep\"}", ] guard let model = Model.deserialize(from: dict) else { return } print(model) struct Model: SmartCodable { var hobby: Hobby? } struct Hobby: SmartCodable { var name: String = "" } ``` -------------------------------- ### Swift Implementation for Flattened Parsing with Codable Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Detailed Swift implementation using Codable, including custom CodingKeys for nested and mapped properties. ```swift struct Remark: Codable { var judge: String var content: String } struct Player: Codable { let name: String let age: Int let nativePlace: String let grossScore: CGFloat let scores: [CGFloat] let remarks: [Remark] // 当前容器中需要包含的key enum CodingKeys: String, CodingKey { case name = "player_name" case age case nativePlace = "native_Place" case scoreInfo } enum ScoreInfoCodingKeys: String, CodingKey { case grossScore = "gross_score" case scores case remarks } struct RemarkCodingKeys: CodingKey { var intValue: Int? {return nil} init?(intValue: Int) {return nil} var stringValue: String //json中的key init?(stringValue: String) { self.stringValue = stringValue } static let content = RemarkCodingKeys(stringValue: "content")! } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .name) self.age = try container.decode(Int.self, forKey: .age) self.nativePlace = try container.decode(String.self, forKey: .nativePlace) let scoresContainer = try container.nestedContainer(keyedBy: ScoreInfoCodingKeys.self, forKey: .scoreInfo) self.grossScore = try scoresContainer.decode(CGFloat.self, forKey: .grossScore) self.scores = try scoresContainer.decode([CGFloat].self, forKey: .scores) let remarksContainer = try scoresContainer.nestedContainer(keyedBy: RemarkCodingKeys.self, forKey: .remarks) var remarks: [Remark] = [] for key in remarksContainer.allKeys { //key的类型就是映射规则的类型(Codingkeys) let judge = key.stringValue print(key) /** RemarkCodingKeys(stringValue: "judgeTwo", intValue: nil) RemarkCodingKeys(stringValue: "judgeOne", intValue: nil) RemarkCodingKeys(stringValue: "judgeThree", intValue: nil) */ let keyedContainer = try remarksContainer.nestedContainer(keyedBy: RemarkCodingKeys.self, forKey: key) let content = try keyedContainer.decode(String.self, forKey: .content) let remark = Remark(judge: judge, content: content) remarks.append(remark) } self.remarks = remarks } func encode(to encoder: Encoder) throws { // 1. 生成最外层的字典容器 var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) try container.encode(age, forKey: .age) try container.encode(nativePlace, forKey: .nativePlace) // 2. 生成scoreInfo字典容器 var scoresContainer = container.nestedContainer(keyedBy: ScoreInfoCodingKeys.self, forKey: .scoreInfo) try scoresContainer.encode(grossScore, forKey: .grossScore) try scoresContainer.encode(scores, forKey: .scores) // 3. 生成remarks字典容器(模型中结构是数组,但是我们要生成字典结构) var remarksContainer = scoresContainer.nestedContainer(keyedBy: RemarkCodingKeys.self, forKey: .remarks) for remark in remarks { var remarkContainer = remarksContainer.nestedContainer(keyedBy: RemarkCodingKeys.self, forKey: RemarkCodingKeys(stringValue: remark.judge)!) try remarkContainer.encode(remark.content, forKey: .content) } } } ``` -------------------------------- ### HandyJSON Inheritance Parsing Source: https://github.com/iammccc/smartcodable/blob/main/Document/QA/QA2.md Example demonstrating how HandyJSON automatically handles inherited properties without requiring subclasses to implement additional methods. ```swift class BaseModel: HandyJSON { var name: String = "" required init() { } } class Model: BaseModel { var age: Int = 0 } let dict = [ "name": "小明", "age": 10 ] as [String : Any] guard let model = Model.deserialize(from: dict) else { return } print(model.age) // 10 print(model.name) // 小明 ``` -------------------------------- ### Key Renaming with SmartDecodingOption Source: https://github.com/iammccc/smartcodable/blob/main/Document/Usages/Usages.md Illustrates how to rename keys during decoding using SmartDecodingOption, specifically with the .key(.fromSnakeCase) strategy. ```swift let option1: SmartDecodingOption = .key(.fromSnakeCase) guard let model1 = TwoModel.deserialize(from: dict1, options: [option1]) else { return } ``` -------------------------------- ### Inherited Decoding with super.init(from: decoder) Source: https://github.com/iammccc/smartcodable/wiki/1.-Codable:-Basics-&-Usage Demonstrates how to decode a subclass (Point3D) that inherits from a Codable superclass (Point2D). It shows the use of `super.init(from: decoder)` to handle the decoding of the superclass's properties. ```swift class Point2D: Codable { var x = 0.0 var y = 0.0 enum CodingKeys: CodingKey { case x case y } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.x = try container.decode(Double.self, forKey: .x) self.y = try container.decode(Double.self, forKey: .y) } } class Point3D: Point2D { var z = 0.0 enum CodingKeys: CodingKey { case z case point2D } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.z = try container.decode(Double.self, forKey: .z) try super.init(from: decoder) } } let json = """ { "x" : 1, "y" : 2, "z" : 3 } """ guard let point = json.decode(type: Point3D.self) else { return } print(point.x) print(point.y) print(point.z) //此时的打印结果是: // 1.0 // 2.0 // 3.0 ``` -------------------------------- ### HandyJSON Struct Model Declaration Source: https://github.com/iammccc/smartcodable/blob/main/Explore&Contribute/CompareWithHandyJSON.md Example of declaring a struct-based model using HandyJSON. ```swift import HandyJSON struct HandyModel: HandyJSON { var name: String = "" } ```