kemchenj / kemchenj.github.io

Source code of my blog ↓↓↓↓↓
https://kemchenj.github.io
6 stars 3 forks source link

Codable 的迁移方案 | kemchenj #27

Open kemchenj opened 7 years ago

kemchenj commented 7 years ago

https://kemchenj.github.io/2017-10-13/

ZHocean123 commented 7 years ago

请教一个问题: “这里偷懒没有转成 MoyaError 再抛出” 这里统一的error格式对于后续的错误处理有什么好的帮助吗,或者说服务端定义的业务error(就是这两个 var statusCode: Int var message: String)也转换成MoyaError吗? 这里需要扩展MoyaError以支持statusCode和message吗? 或者说使用MoyaError的.underlying包装自己的error吗? 对这块一直没有什么明确的思路啊(T_T)

kemchenj commented 7 years ago

@ZHocean123 你可以想象一下写网络层的人不是你,你只负责搭建 UI 和调用网络层的 API,那网络层只有一种 Error 类型需要你处理会不会好一点?统一的 Error 类型对于调用方来说是一个很重要的约定,约定只要处理这一种 Error 就可以了。对于我来说,理想状态下,每个模块应该都抽象一个自己的 Error 类型出来。

服务端定义的业务 error,MoyaError 满足不了这个需求也不应该满足这个需求,如果你觉得有必要的话,可以定义一个自己的 NetworkError,把服务端的业务 error 和 MoyaError 都包含进去,理论上说这么说会让代码更加健壮,例如说你想把 Moya 换了或者 MoyaError 改了,你也只需要处理 MoyaError 转换到 NetworkError 的这个过程就行了,而不需要去处理每一个 ViewController 里的 MoyaError

至于说文章里的那一句这里偷懒没有转成 MoyaError 再抛出,是因为 MoyaError 已经在这个 Pull Request 里加上了 objectMapping 这个枚举值来表示解析错误的情况了,所以我才说应该要转成 MoyaError 再抛出。本来我是有稍微提一下这个 PR 的,但发表的时候觉得跟我要说的内容无关,最后就删了。

shanyanhai commented 7 years ago

看了好多文章 博主写的好多都是我也琢磨过的- -, 这个里面有关注么 难道只能mark一下

kemchenj commented 7 years ago

@shanyanhai RSS 订阅或者 Twitter 关注我都可以

Pircate commented 6 years ago

每一次解析都创建一个JSONDecoder对象会不会开销太大,可以写成类属性吗?

kemchenj commented 6 years ago

@Ginxx 我的答案是,不会,最好不要,这里看似有很大的优化的空间,但实际上并没有,理由有两个:

第一: JSONDecoder 内部保存着一个状态机,解析的函数并不是线程安全的,如果只用一个实例的话,多线程访问可能会产生错误。

如果要求达到线程安全,并且只使用一个 Decoder,那在并发的情况下会有点糟糕,因为同一时间你只能进行一个 decode 行为。为了避免这样的状况,去构建一个 Decoder 的重用池,那整体的复杂度就上去了,并且重用机制也会带来性能消耗,你确定会比直接创建一个 JSONDecoder 消耗更低吗?

而如果你并发的情况并不多,那 JSONDecoder 还会是你的性能瓶颈吗?

第二: 移动端跟服务端不同,JSON 解析绝对是一个低频次的操作,我现在工作的公司是做股票的,一个页面多个接口 3 秒一次轮询, JSONDecoder 的创建开销也远远算不上是瓶颈

我个人的看法是,不到必要的时候,不要去做优化,写好逻辑,构建好一个清晰的抽象会更加重要

Pircate commented 6 years ago

@kemchenj 感谢大佬回答,纠结这个好久了。

kemchenj commented 6 years ago

@Pircate 我这两天翻了一下源码,发现我之前的理解有个很低级的错误😨,JSONDecoder 这个类只保存了一些 decodingStrategy,然后在 decode 方法被调用时,使用这些解析策略去生成 _JSONDecoder 的实例,所以 decode 是一个无副作用的方法,不会存在线程问题

open func decode<T : Decodable>(_ type: T.Type, from data: Data) throws -> T {
    let topLevel: Any
    do {
       topLevel = try JSONSerialization.jsonObject(with: data)
    } catch {
        throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: error))
    }

    let decoder = _JSONDecoder(referencing: topLevel, options: self.options)
    guard let value = try decoder.unbox(topLevel, as: type) else {
        throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: [], debugDescription: "The given data did not contain a top-level value."))
    }

    return value
}
Pircate commented 6 years ago

@kemchenj 这个我也去看源码了,但是结论还是一样的对吧,没必要去创建一个JSONDecoder单例。

LockLight commented 6 years ago

atom.xml ,feed,rss 这些关键字都试过了 ,没有找到博主的RSS订阅源..

kemchenj commented 6 years ago

@LockLight 加上了

LockLight commented 6 years ago

@kemchenj 反应神速,谢谢

yonfong commented 3 years ago

请问下 能提供一个 完整的demo吗?