Code Monkey home page Code Monkey logo

intsig171 / smartcodable Goto Github PK

View Code? Open in Web Editor NEW
342.0 6.0 37.0 8.03 MB

SmartCodable is a data parsing library based on Codable. It is simple to use, with robust compatibility being one of its main features. SmartCodable 是基于Codable实现的数据解析库。简单易用,强悍的兼容性是SmartCodable的主要特点。 表层API和功能几乎和HandyJSON一致,支持快速的迁移。

Home Page: https://smart-codable.vercel.app

License: MIT License

Ruby 0.33% Swift 99.67%
codable handyjson json mapping serialization swift swift-codable

smartcodable's Introduction

SmartCodable

你好,世界 👋

  • 📌: Focusing on Swift & iOS
  • 🛠️: Creator of applications and frameworks
  • 💬: QQ群(865036731)
  • 👀: 掘金博客

smartcodable's People

Contributors

dgpgith avatar intsig171 avatar miles-matheson 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

smartcodable's Issues

使用UInt32等类型来接收字符串类型的时间戳,解析出来的结果是nil。

微信支付的时间戳类型是UInt32,后台返回是的字符串。导致微信支付时报错”签名认证失败“。为了解决问题,我暂时用TimeInterval替换 UInt32,替换后微信支付正常。

struct Model: SmartCodable {
var timestamp: UInt32?
}

let dic: [String : Any] = [
"timestamp": "1721721316"
]

let model = Model.deserialize(from: dic)
model.timestamp 打印出来为nil。

兼容类String型时 int值为1时解析不出来

 // demo中的代码
    let dict = [
        "string1": 1, //解析不出来!!
        "string2": 345.0,
        "string3": [],
        "string4": NSNull()
    ] as [String : Any]
    
    guard let feed = CompatibleString.deserialize(from: dict) else { return }
    print("string1的值为", feed.string1)
    print("string2的值为", feed.string2)
    print("string3的值为", feed.string3)
    print("string4的值为", feed.string4 ?? "")

字符串的Model化相关问题

您好,
字符串的Model可以将value为String类型的json转换为对应的model,但如果json的最外层是数组,似乎无法成功转换为对应的model,例如:
let dict: [String: Any] = [
"hobby": "{"name":"sleep"}",
]
如上这种情况可以成功转换为model,
而如果是如下这种情况,似乎无法成功转换为model
let dict: [String: Any] = [
"hobby": "[{"name":"sleep"}]",
]

在阅读源码后发现如下地方是产生问题的原因:
WechatIMG257

由于此时T为数组类型的model([M�odel].type),而value为string,所以会return nil,不会继续解析。
所以我在这里加了一个判断,才得以完成之后的解析,最后成功转换为对应的model。
WechatIMG258
所以此问是想了解一下,这样的改动会不会对整体功能有影响,或者影响到其他相关功能呢?

Int32等接收,转化不了String类型的int值

后端返回了一个int值的字符串,如"11111111",此时我用Int32/Int16/Int64/UInt/Uint16/UInt32等类型去接收,会转化不出来,只能使用Int去接收。能否兼容一下Int的其它类型。

缺键状态的错误提示问题

对于很多JSON框架来说, 发缺少键的JSON是常态, 之前用HandyJSON时, 所有属性都是设置为(?)可选类型, decode默认无键为nil, encode也会在值解包为nil时发送缺键的JSON
所以能不能把无键的提示从error降级到debug

AnyHashable

var dps : [AnyHashable : SmartAny] = [:]

AnyHashable 这个类型需要帮着支持下,或者怎么解决

泛型反序列化问题

struct Response<Content: Any>: SmartCodable {
    var status: String?
    @SmartAny
    var content: Content?
    var errorCode: String?
}

struct Check: SmartCodable {
    var token: String?
}

let JSON = """
{"status":"SUCCESS","errorCode":null,"content":{"token":"b3d0e432037d9db9e468a95250dead5c"}}
"""

let resp = Response<T>.deserialize(from: JSON) 

HandyJSON 是支持这样的反序列的,但 SmartCodable 会有下面的报错:

========================  [Smart Decoding Log]  ========================
Response<Check> 👈🏻 👀
   |- content: Expected to decode SmartAny<Optional<Check>> but found a dictionary instead.
=========================================================================

只能通过自定义策略还是有其他的解决方法?

map映射是如何使用的?

刚更新到4.1.1

public struct EGNetworkRecordWorkflowTaskRequest: SmartCodable {
    public init() {}
    public var workflowAgentId: String = "assistants.voice_summary.bot.lite"
    public var params: EGNetworkRecordWorkflowTaskParameters?
    
    public static func mappingForKey() -> [SmartKeyTransformer]? {
        return [
            CodingKeys.workflowAgentId <--- "workflow_agent_id"
        ]
    }
}

public struct EGNetworkRecordWorkflowTaskParameters: SmartCodable {
    public init() {}
    public var filePath: String?
    public var language: EGRecordLangague?
    
    public static func mappingForKey() -> [SmartKeyTransformer]? {
        return [
            CodingKeys.filePath <--- "file_path"
        ]
    }
}

toJSONString()结果是{\"params\":{\"filePath\":\"files\\/uploads\\/2024-08-08\\/1723104522新录音 8.m4a\",\"language\":\"en-US\"},\"workflowAgentId\":\"assistants.voice_summary.bot.lite\"}, workflowAgentIdfilePath没有映射键

使用SmartAny遇到类型转化错误

解析数据:

{"code":1,"data":{"index":"4","msg":"上传成功","size":1780},"msg":"success","rid":"Dg0S"}

使用Moya进行网络请求,返回结果中使用泛型的方式进行解析上面的数据

 let jsonString = String(data: moyaResponse.data, encoding: String.Encoding.utf8) ?? ""
guard let data = try? moyaResponse.mapModel(T.self,jsonString: jsonString) else { return }

extension Response{
    func mapModel<T: SmartCodable>(_ type: T.Type, jsonString: String) throws -> T{
        guard let model = type.deserialize(from:jsonString) else { throw MoyaError.jsonMapping(self)}
        return model
    }
}

struct ResponseData<T: SmartCodable>: SmartCodable{
    var code: Int = 0
    var msg: String = ""
    var data: T?
}

崩溃位置,打印了一下value是1780,识别类型错误

    func unbox(_ value: Any, as type: String.Type) throws -> String? {
        guard !(value is NSNull) else { return nil }
        if let tranform = cache.tranform(decodedValue: value, for: codingPath) as? String {
            return tranform
        }
        guard let string = value as? String else {
            throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
        }
        
        return string
    }
image

建议完善的单元测试

基础库的稳定性极为重要,这个项目缺少完整单元测试,无法确定是否具备生产可用的条件,建议召集社区力量完善单元测试,以100%代码覆盖为目标建设。

能否增加自定义转换规则

您好
得益于类HandyJSON的API,我们也比较平滑地迁移到了Codable协议的方案。
迁移的过程中也发现了一些问题。希望作者能够参考一下提议。

增加模型内部对每个字段的转换规则来支撑一下场景(HandyJSON已支持)。
例1:
var createDate: Date?
服务端有可能返回字符串(如:2024-04-07)也有可能返回时间戳。

例2:
var createDate: Date?
var updateDate: Date?
这两个字段中一个返回了字符串(如:2024-04-07),一个返回了时间戳。

4.0.4版本解析结果不符合期望

struct Room: SmartCodable {
var game: Game?
}

struct Game: SmartCodable {}

这种结构下,当json返回room结构中的game为null时。
3.4.5版本的game为null。
4.0.4版本的game不为null。

SmartAny的问题

我用主页说明的方式使用SmartAny代码得出的peel值都是false, 请验证一下

新版本的一些提问

一: 旧版本用

struct Model: SmartCodable {
    var name: String = ""
    var age: Int = 0
    
    enum CodingKeys: String, CodingKey {
        case name = "nickName"
        case age
    }
}

新版本是必须要改成这样吗

struct Model: SmartCodable {
    var name: String = ""
    var age: Int = 0
    
    enum CodingKeys: CodingKey {
        case name
        case age
    }
    
    static func mapping() -> [MappingRelationship]? {
        [
            CodingKeys.name <--- "nickName",
            CodingKeys.age <--- "age"  
        ]
    }
}

二: enum和mapping()是否必须要写, enum不写是否会导致所有数据不解析, 如上面的age不需要映射的字段是否需要在mapping()里声明

三: mapping()有没有自定义方法, 比如以下将字符串解析成Int数组

struct Model: SmartCodable {
    var aList: [Int] = []
}

public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let temString = try container.decodeIfPresent(String.self, forKey: . aList) {
            if temString.count > 0 {
                aList = temString.split(separator: ",").compactMap { Float($0.trimmingCharacters(in: .whitespacesAndNewlines)) }
            }
        }
}

四: @SmartOptional 是否已经弃用了

五: 我有上百个Model需要从2.x版本改3.x版本, 有什么其他建议吗

感谢解答

感谢您的作品,当时在使用过程中遇到了崩溃

有两处崩溃,但是崩溃数量非常少,我也没有查到到底是哪种情况
1: 0 SmartCodable 0x18080 LogCache.alignTypeNamesInAllSnapshots() + 156 (LogCache.swift:156)
1 SmartCodable 0x16e40 LogCache.formatLogs() + 31 (LogCache.swift:31)
2 SmartCodable 0x3b904 specialized static SmartLog.printCacheLogs(in:) + 73 (SmartLog.swift:73)
3 SmartCodable 0x30520 SmartJSONDecoder.decode(_:from:) + 55 (SmartJSONDecoder.swift:55)

2: 0 SmartCodable 0x298bc specialized NativeDictionary.insert(at:key:value:) + 40 (:40)
1 SmartCodable 0x18d60 specialized Dictionary.Variant.setValue(:forKey:) + 192 (:192)
2 SmartCodable 0x16c1c LogCache.cacheLog(
:className:) + 145 (LogCache.swift:145)
3 SmartCodable 0x36df4 logInfo #1
() in SmartJSONKeyedDecodingContainer.smartDecode (forKey:entry:) + 920
4 SmartCodable 0x366a0 SmartJSONKeyedDecodingContainer.smartDecode(forKey:entry:) + 256
(SmartJSONKeyedDecodingContainer+decode.swift:256)
5 SmartCodable 0x34838 SmartJSONKeyedDecodingContainer.decode(
:forKey:) + 25 (SmartJSONKeyedDecodingContainer+decode.swift:25)
6 SmartCodable 0x31a2c protocol witness for KeyedDecodingContainerProtocol.decode(_:forKey:) in conformance SmartJSONKeyedDecodingContainer + 28 (:28)

日志错误打印

我加载的json数据正常,且有需要解析的字段,SmartLog error提示 错误类型: '找不到键的错误'

private func loadCircleData() {
        
        guard let path = Bundle.main.path(forResource: "circle_data", ofType: "json") else { return }
        
        do {
            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
            let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
            if let jsonArray = jsonArray as? [[String: Any]] {
                if let modelList = [TYCircleHomeListModel].deserialize(array: jsonArray) {
                    let randomList = modelList.shuffled().compactMap { $0 }
                    
                    if (self.pageIndex == 1) {
                        self.dataSource = randomList
                    }
                    
                    
                    if (self.pageIndex > 1) {
                        if (self.pageIndex >= 10) {
                            self.endRefreshing()
                            self.tableView.mj_footer?.state = .noMoreData
                            return
                        }
                        
                        self.dataSource.append(contentsOf: randomList)
                    }
                    
                    DispatchQueue.main.asyncAfter(deadline: .now()+1.25) {
                        self.tableView.reloadData()
                        self.endRefreshing()
                    }
                }
            }
        } catch {
            print("Error parsing JSON: \(error)")
        }
    }

============= 💔 [SmartLog Error] 💔 =============
错误类型: '找不到键的错误'
模型名称:Array
数据节点:Index 5
属性信息:videoUrl
错误原因: No value associated with key CodingKeys(stringValue: "videoUrl", intValue: nil) ("videoUrl").

枚举类型不匹配的时候没有使用默认值

3.3.1中,json转模型,枚举类型不匹配的时候,没有使用默认值。
例如:下例中默认值都是.good

struct QLSocial: SmartCodable {
var n_type: QLPersonType = .good
var g_type: QLPersonType = .good
}

public enum QLPersonType: Int, SmartCaseDefaultable {
    static var defaultCase: QLPersonType = .normal
    case normal = 0
    case good = 1
    case best = 2
}

let json1 = """
{
"n_type": 2,
"g_type": "2"
}
"""

let model1 = QLSocial.deserialize(from: json1)

打印结果:
- n_type : .QLPersonType.best
- g_type : .QLPersonType.normal

moya response is data

open func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable
在moya请求返回直接是data, codable亦支持

你可能需要增加 public static func deserialize(data: Data?) -> Self?

类型转换失败 json中为int double Bool类型字符串,分别转为int

fileprivate let jsonStr = """
{
    "age": "18",
    "weight": "65.4",
    "sex": "1"
}
"""
//模型
struct ZJSmartCodableModel: SmartCodable {
    var age: Int?
    var weight: Double?
    var sex: Bool?
}

使用该方式转化失败
let model = ZJSmartCodableModel.deserialize(from: jsonStr)!
日志中输出

========================  [Smart Decoding Log]  ========================
ZJSmartCodableModel 👈🏻 👀
   |- age   : Expected to decode Int but found a string instead.
   |- weight: Expected to decode Double but found a string instead.
   |- sex   : Expected to decode Bool but found a string instead.
=========================================================================

解析失败

image guard let tempKey = userKey, let originDict = superDe.userInfo[tempKey] as?[String : Any] else {} 这行代码有问题,originDict返回的是一个json字符串,所以解析失败

局部的值解析策略支持SmartDataTransformer

局部的值解析策略
struct SmartModel: SmartCodable {
var date1: Date?
var date2: Date?
var url: URL?

// value的解析策略
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)
    ]
}

}

有没有计划对泛型进行支持

在网络接口的封装中有个典型的场景是封装上级通用model例如下图,这个场景下使用泛型来动态定义model中的业务成员类型
image

刚才试了下,好像默认不支持泛型的嵌套解析,自定义实现了一下decoder,如果json字符串不对就进断言里了,不知道咋能避免这个难问题

JSON中值和Model定义的类型不一致 解析失败(类型不兼容)

fileprivate let jsonStr = """
{
    "username": "yuhanle",
    "age": "18",
    "weight": 65.4,
    "sex": 1,
    "location": "Toronto, Canada",
}
"""


// 模型定义
struct ZJSmartCodableModel: SmartCodable {
    var username: String?
    var age: Int?
    var weight: Double?
    var sex: Int?
    var location: String?
}

//模型解析
let people = ZJSmartCodableModel.deserialize(from: jsonStr)!

解析后错误提示

========================  [Smart Decoding Log]  ========================
ZJSmartCodableModel 👈🏻 👀
   |- age: Expected to decode Int but found a string instead.
=========================================================================

使用版本 4.0.3和4.0.4 都是一样的结果

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.