Code Monkey home page Code Monkey logo

codablewrapper's Introduction

Requirements

Xcode Minimun Deployments Version
Xcode15 >= iOS13 / macOS11 1.0+
< Xcode15 < iOS13 / macOS11 0.3.3

About

The project objective is to enhance the usage experience of the Codable protocol using the macro provided by Swift 5.9 and to address the shortcomings of various official versions.

Feature

  • Default value
  • Basic type automatic convertible, between String Bool Number etc.
  • Custom multiple CodingKey
  • Nested Dictionary CodingKey
  • Automatic compatibility between camel case and snake case
  • Convenience Codable subclass
  • Transformer

Installation

CocoaPods

pod 'CodableWrapper'

Swift Package Manager

https://github.com/winddpan/CodableWrapper

Example

@Codable
struct BasicModel {
    var defaultVal: String = "hello world"
    var defaultVal2: String = Bool.random() ? "hello world" : ""
    let strict: String
    let noStrict: String?
    let autoConvert: Int?

    @CodingKey("hello")
    var hi: String = "there"

    @CodingNestedKey("nested.hi")
    @CodingTransformer(StringPrefixTransform("HELLO -> "))
    var codingKeySupport: String

    @CodingNestedKey("nested.b")
    var nestedB: String

    var testGetter: String {
        nestedB
    }
}

final class CodableWrapperTests: XCTestCase {
    func testBasicUsage() throws {
        let jsonStr = """
        {
            "strict": "value of strict",
            "autoConvert": "998",
            "nested": {
                "hi": "nested there",
                "b": "b value"
            }
        }
        """

        let model = try JSONDecoder().decode(BasicModel.self, from: jsonStr.data(using: .utf8)!)
        XCTAssertEqual(model.defaultVal, "hello world")
        XCTAssertEqual(model.strict, "value of strict")
        XCTAssertEqual(model.noStrict, nil)
        XCTAssertEqual(model.autoConvert, 998)
        XCTAssertEqual(model.hi, "there")
        XCTAssertEqual(model.codingKeySupport, "HELLO -> nested there")
        XCTAssertEqual(model.nestedB, "b value")

        let encoded = try JSONEncoder().encode(model)
        let dict = try JSONSerialization.jsonObject(with: encoded) as! [String: Any]
        XCTAssertEqual(model.defaultVal, dict["defaultVal"] as! String)
        XCTAssertEqual(model.strict, dict["strict"] as! String)
        XCTAssertNil(dict["noStrict"])
        XCTAssertEqual(model.autoConvert, dict["autoConvert"] as? Int)
        XCTAssertEqual(model.hi, dict["hello"] as! String)
        XCTAssertEqual("nested there", (dict["nested"] as! [String: Any])["hi"] as! String)
        XCTAssertEqual(model.nestedB, (dict["nested"] as! [String: Any])["b"] as! String)
    }
}

Macro usage

@Codable

  • Auto conformance Codable protocol if not explicitly declared

    // both below works well
    
    @Codable
    struct BasicModel {}
    
    @Codable
    struct BasicModel: Codable {}
  • Default value

    @Codable
    struct TestModel {
        let name: String
        var balance: Double = 0
    }
    
    // { "name": "jhon" }
  • Basic type automatic convertible, between String Bool Number etc.

    @Codable
    struct TestModel {
        let autoConvert: Int?
    }
    
    // { "autoConvert": "998" }
  • Automatic compatibility between camel case and snake case

    @Codable
    struct TestModel {
        var userName: String = ""
    }
    
    // { "user_name": "jhon" }
  • Member Wise Init

    @Codable
    public struct TestModel {
        public var userName: String = ""
    
        // Automatic generated
        public init(userName: String = "") {
            self.userName = userName
        }
    }

@CodingKey

  • Custom CodingKeys

    @Codable
    struct TestModel {
        @CodingKey("u1", "u2", "u9")
        var userName: String = ""
    }
    
    // { "u9": "jhon" }

@CodingNestedKey

  • Custom CodingKeys in nested dictionary

    @Codable
    struct TestModel {
        @CodingNestedKey("data.u1", "data.u2", "data.u9")
        var userName: String = ""
    }
    
    // { "data": {"u9": "jhon"} }

@CodableSubclass

  • Automatic generate Codable class's subclass init(from:) and encode(to:) super calls

    @Codable
    class BaseModel {
        let userName: String
    }
    
    @CodableSubclass
    class SubModel: BaseModel {
        let age: Int
    }
    
    // {"user_name": "jhon", "age": 22}

@CodingTransformer

  • Transformer between in Codable / NonCodable model

    struct DateWrapper {
        let timestamp: TimeInterval
    
        var date: Date {
            Date(timeIntervalSince1970: timestamp)
        }
    
        init(timestamp: TimeInterval) {
            self.timestamp = timestamp
        }
    
        static var transformer = TransformOf<DateWrapper, TimeInterval>(fromJSON: { DateWrapper(timestamp: $0 ?? 0) }, toJSON: { $0.timestamp })
    }
    
    @Codable
    struct DateModel {
        @CodingTransformer(DateWrapper.transformer)
        var time: DateWrapper? = DateWrapper(timestamp: 0)
        
        @CodingTransformer(DateWrapper.transformer)
        var time1: DateWrapper = DateWrapper(timestamp: 0)
        
        @CodingTransformer(DateWrapper.transformer)
        var time2: DateWrapper?
    }
    
    class TransformTest: XCTestCase {
        func testDateModel() throws {
            let json = """
            {"time": 12345}
            """
    
            let model = try JSONDecoder().decode(DateModel.self, from: json.data(using: .utf8)!)
            XCTAssertEqual(model.time?.timestamp, 12345)
            XCTAssertEqual(model.time?.date.description, "1970-01-01 03:25:45 +0000")
    
            let encode = try JSONEncoder().encode(model)
            let jsonObject = try JSONSerialization.jsonObject(with: encode, options: []) as! [String: Any]
            XCTAssertEqual(jsonObject["time"] as! TimeInterval, 12345)
        }
    }

Star History

Star History Chart

codablewrapper's People

Contributors

rakuyomo avatar scyano avatar winddpan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

codablewrapper's Issues

与CleanJSON一起用会Crash

CodableWrapper的0.3.3版本与CleanJSON的1.0.9版本一起用,因为大家都重写了decode过程,导致Crash

希望能支持cocoapods引用1.0.0版本

如题
现在的项目,都是从历史来的,要完全脱离cocoapods还是很难的,但是我们的版本是符合的,最低安装版本为iOS13,我们希望能在新需求中,使用swift5.9的新特性来解析codable,以提高解析安全性。如果cocoapods和spm混用的话,那我的cocoapods子库无法引用到CodableWrapper,所以只能使用cocoapods来接入。
如果CodableWrapper的cocoapods的版本不能更新,那我们不会考虑接入CodableWrapper
希望作者考虑一下这个问题,感谢!

改动这么大...

这。。还能继续在正式环境里用吗?
新版本改动这么大..一更新都报错..

@CodableWrapper 命名改了么?

(defaultValue: 也改了么?替代的用法是啥?

property wrapper的限制

遇到几个问题:
1, 如果一个model, 在不同的场合下要转换成不同的JSON, 这个怎么处理?
2,property wrapper无法嵌套, 如果用了这个库, 那么model里边就没办法再使用其它库的property wrapper了。

Optional 类型无默认值问题

有些参数存在服务器字段缺失或没有值的问题,我也不需要设置默认值(或者说,没有办法为某些属性设置一个合理的默认值)。
声明 Optional 类型的属性:

@Codec("pic") var imageURL: URL?

会报编译器红色错误:❌ type of expression is ambiguous without more context

要将属性设置成有默认值的非可选类型,或者:

@Codec("pic") var imageURL: URL? = nil

才可以编译通过。

【问题】Optional 类型的语义就是:要么它存在值,不存在值默认就是 nil,在声明时还需要主动赋值 nil 有点多余。

不建议用在正式项目

因为用到了mirror反查系统内部属性,thread注入参数这些不稳定的实现。和swift追求静态语言的原则不太符,活活把swift写错了oc

改动这么大...

这。。还能继续在正式环境里用吗?
新版本改动这么大..一更新都报错..

@CodableWrapper 命名改了么?

(defaultValue: 也改了么?替代的用法是啥?

Equtable协议识别不出来

@Codable
struct ImproveHightligh {
    var name: String?
}

@Codable
struct ImproveSuggestion: Equatable {
    var name = ""
    let code: String?
    var highlightList: [ImproveHightligh]?

    static func == (lhs: ImproveSuggestion, rhs: ImproveSuggestion) -> Bool {
        return lhs.name == rhs.name && lhs.code == rhs.code
    }
}

这种写法会报错:Type 'ImproveSuggestion' does not conform to protocol 'Equatable'

有两种方式可以解决,我目前使用了extension的方式处理

/// 方式1,为模型ImproveHightligh添加Equtable
@Codable
struct ImproveHightligh: Equatable {
    var name: String?
}


/// 方式2,使用扩展
extension ImproveSuggestion: Equatable {
    static func == (lhs: ImproveSuggestion, rhs: ImproveSuggestion) -> Bool {
        return lhs.name == rhs.name && lhs.code == rhs.code
    }
}

推测可能是Equtable本身会对代码进行解析并自动实现func ==,Equtable解析的过程与与宏定义有冲突,可能是SwiftMacro的bug

与 wcdb.swift 一起使用,@Codec 与 wcdb的 tablecodable 中 coding定义 导致崩溃

`struct ExaminationItem: Codable {
static let tableName = "ExamTable"

var id: String
var type: String
var typename: String
var fathertype: String
var fathertypename: String
var searchwd: String?
var biaozhu: String?


var timu: [ExamOptionItem] = []
var xuanxiang: [ExamOptionItem] = []
var jiexi: [ExamOptionItem] = []
var daan: [String] = []

@Codec var showAnalyze: Bool = false
@Codec var isshoucang: Bool = false
@Codec var timuleibie: Bool = false

var noXunxiang: Bool {
    get {
        return daan.count <= 0
    }
}

var isRadio: Bool {
    get {
        return daan.count <= 1
    }
}

}
extension ExaminationItem: TableCodable {
enum CodingKeys: String, CodingTableKey {
typealias Root = ExaminationItem
static let objectRelationalMapping = TableBinding(CodingKeys.self)
case id
case type
case typename
case fathertype
case fathertypename
case searchwd
case biaozhu
case timu
case xuanxiang
case jiexi
case daan
case isshoucang
case timuleibie
}
}`

截屏2021-11-14 下午2 18 01

请教下 需要怎么解决

version:0.3.3 时奔溃。希望能找找原因。

import CodableWrapper

struct LocationModel: Codable {

@Codec("Id")
var id: String? = nil
@Codec("Value")
var value: String? = nil 
@Codec("Children")
var child: [LocationModel]? = nil

}

Test:

    let jsonString2 =
    "[{\"Value\":null,\"Label\":\"State/Province\",\"Id\":\"a0Mp0000007ANEoEAO\",\"Children\":[{\"Value\":\"Bangkok\",\"Label\":\"City\",\"Id\":\"a0Mp0000007ANe7EAG\",\"Children\":[{\"Value\":\"Bang Kapi\",\"Label\":\"District\",\"Id\":\"a0Mp0000007ANeCEAW\",\"Children\":null}]}]}]".data(using: .utf8)!
    
    let decoder = JSONDecoder()
    let model = try! decoder.decode([LocationModel].self, from: jsonString2)
    logInfo("json = \(model.toJSONString())")

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.