继承自 JSONDecoder,在标准库源码基础上做了改动,以解决 JSONDecoder 各种解析失败的问题,如键值不存在,值为 null,类型不一致。
只需将 JSONDecoder 替换成 CleanJSONDecoder。
To run the example project, clone the repo, and run pod install from the Example directory first.
- iOS 9.0
- Swift 5.2
CleanJSON is available through CocoaPods or Carthage. To install it, simply add the following line to your Podfile or Cartfile:
pod'CleanJSON'github"Pircate/CleanJSON"import CleanJSONletdecoder=CleanJSONDecoder()try decoder.decode(Model.self, from: data)
// 支持直接解析符合 JSON 规范的字典和数组
try decoder.decode(Model.self, from:["key": value])对于枚举类型请遵循 CaseDefaultable 协议,如果解析失败会返回默认 case
Note: 枚举使用强类型解析,关联类型和数据类型不一致不会进行类型转换,会解析为默认 case
enumEnum:Int,Codable,CaseDefaultable{case case1
case case2
case case3
staticvardefaultCase:Enum{return.case1
}}可以通过 valueNotFoundDecodingStrategy 在值为 null 或类型不匹配的时候自定义解码,默认策略请看这里
structCustomAdapter:JSONAdapter{
// 由于 Swift 布尔类型不是非 0 即 true,所以默认没有提供类型转换。
// 如果想实现 Int 转 Bool 可以自定义解码。
func adapt(_ decoder:CleanDecoder)throws->Bool{
// 值为 null
if decoder.decodeNil(){returnfalse}iflet intValue =try decoder.decodeIfPresent(Int.self){
// 类型不匹配,期望 Bool 类型,实际是 Int 类型
return intValue !=0}returnfalse}
// 为避免精度丢失所以没有提供浮点型转整型
// 可以通过下面适配器进行类型转换
func adapt(_ decoder:CleanDecoder)throws->Int{guardlet doubleValue =try decoder.decodeIfPresent(Double.self)else{return0}returnInt(doubleValue)}
// 可选的 URL 类型解析失败的时候返回一个默认 url
func adaptIfPresent(_ decoder:CleanDecoder)throws->URL?{returnURL(string:"https://google.com")}}
decoder.valueNotFoundDecodingStrategy =.custom(CustomAdapter())可以通过 JSONStringDecodingStrategy 将 JSON 格式的字符串自动转成 Codable 对象或数组
// 包含这些 key 的 JSON 字符串转成对象
decoder.jsonStringDecodingStrategy =.containsKeys([])
// 所有 JSON 字符串都转成对象
decoder.jsonStringDecodingStrategy =.all为 keyDecodingStrategy 新增了一个自定义映射器,可以只映射指定 coding path 的 key
decoder.keyDecodingStrategy =.mapper([["snake_case"]:"snakeCase",["nested","alpha"]:"a"])使用 Moya.Response 自带的 map 方法解析,传入 CleanJSONDecoder
provider =MoyaProvider<GitHub>()
provider.request(.zen){ result inswitch result {caselet.success(response):letdecoder=CleanJSONDecoder()letmodel= response.map(Model.self, using: decoder)caselet.failure(error):
// this means there was a network failure - either the request
// wasn't sent (connectivity), or no response was received (server
// timed out). If the server responds with a 4xx or 5xx error, that
// will be sent as a ".success"-ful response.
}}provider =MoyaProvider<GitHub>()letdecoder=CleanJSONDecoder()
provider.rx.request(.userProfile("ashfurrow")).map(Model.self, using: decoder).subscribe{ event inswitch event {caselet.success(model):
// do someting
case let.error(error):
print(error)}}Pircate, swifter.dev@gmail.com
CleanJSON is available under the MIT license. See the LICENSE file for more info.