亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Swift > 正文

Swift Json實例詳細解析

2020-03-09 17:42:14
字體:
來源:轉載
供稿:網友

前言

客戶端開發項目中,不可避免地需要解析網絡數據---將服務端下發的JSON數據解析成客戶端可閱讀友好的Model。Objective-C下使用最多的是JSONModel,它能在OC Runtime基礎下很好地完成解析工作。那么在純Swift代碼中,這個功能是如何實現的?下面開始我們的探索~

  • 手動解析
  • 原生:Swift4.0 JSONDecoder
  • JSONDecoder 問題 及 解決方案

手動解析

假設一個User類要解析,Json如下:

{ "userId": 1, "name": "Jack", "height": 1.7,}

對應的創建一個User結構體(也可以是類):

struct User { var userId: Int? var name: String? var height: CGFloat?}

把JSON轉成User

在Swift4.0前,我們以手動解析的方式將JSON model化。給User加一個以JSON為參數的初始化方法,代碼如下:

struct User { ... init?(json: [String: Any]) {  guard let userId = json["userId"] as? Int,  let name = json["name"] as? String,  let height = json["height"] as? CGFloat else { return nil }  self.userId = userId  self.name = name  self.height = height }}

依次從json中取出model所需的具體類型的數據,填充到具體對應屬性中。如果其中一個轉換失敗或者沒有值,初始化會失敗返回nil。

如果某個值不需要強校驗,直接取值再賦值,把guard let內的語句去掉。例如,若height不用校驗,可看如下代碼:

struct User { ... init?(json: [String: Any]) {  guard let userId = json["userId"] as? Int,  let name = json["name"] as? String else { return nil }  self.userId = userId  self.name = name  self.height = json["height"] as? CGFloat }}

原生:Swift4.0 JSONDecoder

2017年6月份左右Swift4.0發布,其中一個重大更新就是JSON的加解密。擺脫手工解析字段的繁瑣,聊聊幾行代碼就可將JSON轉換成Model。與Objective-C下的JSONModel極為相似。同樣解析上述例子中的User,Swift4.0可以這么寫:

struct User: Decodable { var userId: Int? var name: String? var height: CGFloat?}let decoder = JSONDecoder()if let data = jsonString.data(using: String.Encoding.utf8) { let user = try? decoder.decode(User.self, from: data)}

so easy~ 與手動解析不同點在于:

1.移除了手寫init?方法。不需要手動解了

2.User實現Decodable協議,協議的定義如下:

/// A type that can decode itself from an external representation.public protocol Decodable { /// Creates a new instance by decoding from the given decoder. /// /// This initializer throws an error if reading from the decoder fails, or /// if the data read is corrupted or otherwise invalid. /// /// - Parameter decoder: The decoder to read data from. public init(from decoder: Decoder) throws}

Decodable協議只有一個方法public init(from decoder: Decoder) throws---以Decoder實例進行初始化,初始化失敗可能拋出異常。慶幸的是,只要繼承Decodable協議,系統會自動檢測類中的屬性進行初始化工作,省去了人工解析的麻煩~

3.使用了JSONDecoder。它是真正的解析工具,主導整個解析過程

讀到這里,是不是覺得人生從黑暗邁向了光明~~

可是,它并不完美...

JSONDecoder問題及方案

解析JSON經常遇到這樣兩種不一致問題:

  • 服務端下發的key跟端上不一致。比如,服務端下發key="order_id",端上定義key="orderId"
  • 服務端下發的日期表達是yyyy-MM-dd HH:mm或者時間戳,但端上是Date類型
  • 服務端下發的基本類型和端上定義的不一致。服務端下發的是String,端上定義的Int,等

前兩個問題JSONDecoder都能很好地解決。

第一個key不一致問題,JSONDecoder有現成的方案。以上面介紹的例子來說,假設服務端返回的key是user_id而不是userId,那么我們可以使用JSONDecoder的CodingKeys像JSONModel一樣對屬性名稱在加解密時的名稱做轉換。User修改如下:

struct User: Decodable { var userId: Int? var name: String? var height: CGFloat?  enum CodingKeys: String, CodingKey {  case userId = "user_id"  case name  case height }}

第二個,Date轉換問題。JSONDecoder也為我們提供了單獨的API:

open class JSONDecoder { /// The strategy to use for decoding `Date` values. public enum DateDecodingStrategy {  /// Defer to `Date` for decoding. This is the default strategy.  case deferredToDate  /// Decode the `Date` as a UNIX timestamp from a JSON number.  case secondsSince1970  /// Decode the `Date` as UNIX millisecond timestamp from a JSON number.  case millisecondsSince1970  /// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format).  case iso8601  /// Decode the `Date` as a string parsed by the given formatter.  case formatted(DateFormatter)  /// Decode the `Date` as a custom value decoded by the given closure.  case custom((Decoder) throws -> Date) } ...... /// The strategy to use in decoding dates. Defaults to `.deferredToDate`. open var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy}

設置好了JSONDecoder屬性dateDecodingStrategy后,解析Date類型就會按照指定的策略進行解析。

類型不一致

至此,JSONDecoder為我們提供了

  • 解析不同key值對象
  • Date類型可自定義轉換
  • Float在一些正負無窮及無值得特殊表示。(出現的概率很少,不作具體說明了)

但遇到基本類型端上與服務端不一致時(比如一個數字1,端上的Code是Int型,服務端下發String:"1"),JSONDecoder會拋出typeMismatch異常而終結整個數據的解析。

這讓人有點懊惱,端上的應用,我們希望它能夠盡可能穩定,而不是某些情況下遇到若干個基本類型不一致整個解析就停止,甚至是 Crash。

如下面表格所示,我們希望類型不匹配時,能夠這么處理:左列代表前端的類型,右列代表服務端類型,每一行代表前端類型為X時,能從服務端下發的哪些類型中轉化,比如String 可以從 IntorFloat轉化。這幾個類型基本能覆蓋日常服務端下發的數據,其它類型的轉化可根據自己的需求擴充。

 


前端
服務端
String Int,Float
Float String
Double String
Bool String, Int
 

 

JSONDecoder沒有給我們便利的這種異常處理的API。如何解決呢?最直接的想法,在具體的model內實現init(decoder: Decoder)手動解析可以實現,但每個都這么處理太麻煩。

解決方案:KeyedDecodingContainer方法覆蓋

研究JSONDecoder的源碼,在解析自定義Model過程中,會發現這樣一個調用關系。

// 入口方法JSONDecoder decoder(type:Type data:Data)  // 內部類,真實用來解析的 _JSONDecoder unbox(value:Any type:Type)  // Model調用init方法 Decodable init(decoder: Decoder)  // 自動生成的init方法調用container Decoder container(keyedBy:CodingKeys)  // 解析的容器 KeyedDecodingContainer decoderIfPresent(type:Type) or decode(type:Type)  // 內部類,循環調用unbox  _JSONDecoder unbox(value:Any type:Type)  ...循環,直到基本類型

最終的解析落到,_JSONDecoder的unbox 及 KeyedDecodingContainer的decoderIfPresent decode方法。但_JSONDecoder是內部類,我們處理不了。最終決定對KeyedDecodingContainer下手,其中部分代碼如下:

extension KeyedDecodingContainer { ....... /// Decode (Int, String) -> Int if possiable public func decodeIfPresent(_ type: Int.Type, forKey key: K) throws -> Int? {  if let value = try? decode(type, forKey: key) {   return value  }  if let value = try? decode(String.self, forKey: key) {   return Int(value)  }  return nil }  .......  /// Avoid the failure just when decoding type of Dictionary, Array, SubModel failed public func decodeIfPresent<T>(_ type: T.Type, forKey key: K) throws -> T? where T : Decodable {  return try? decode(type, forKey: key) }}

上述代碼中,第一個函數decodeIfPresent(_ type: Int.Type, forKey key: K)是以key的信息解析出Int?值。這里覆蓋了KeyedDecodingContainer中的該函數的實現,現在已try?的形式以Int類型解析,解析成功則直接返回,失敗則以String類型解析出一個StringValue,如果解析成功,再把String轉換成Int?值。

為什么要寫第二個函數呢?

場景:當我們Model內有其他的非基本類型的Model,比如其他自定義Model,Dictionary<String, Any>,Array<String>等,當這些Model 類型不匹配或者出錯誤時也會拋出異常,導致整個大Model解析失敗。
覆蓋decodeIfPresent<T>(_ type: T.Type, forKey key: K)可以避免這些場景。至此,當類型過程中出現解析的Optional類型出現不匹配時,我們要不是通過轉換,要不就是給其賦值nil,避免了系統此時直接throw exception導致退出整個解析過程的尷尬。

為何不覆蓋decode方法?decodeIfPresent可以返回Optional值,decode返回確定類型值??紤]到如果Model內如果定義的類型是No-Optional型,那么可以認為開發者確定該值必須存在,如果不存在Model很可能是錯誤的,所以直接fail。

完整擴展代碼點我   (本地下載點我

總結

Swift4.0 JSONDecoder確實為解析數據帶來了極大的便利。使用方式上類似Objective-C下的JSONModel。但實際開發中還是需要一些改造才能更好地服務于我們。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到swift教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
伊人男人综合视频网| 欧美性20hd另类| 91欧美日韩一区| 国产精品福利在线| 热门国产精品亚洲第一区在线| 欧美又大又硬又粗bbbbb| 91在线中文字幕| 97精品国产97久久久久久春色| 国产欧美精品一区二区三区-老狼| 久久精品国产一区| 精品国产乱码久久久久久虫虫漫画| 日韩av中文字幕在线播放| 日韩av在线网址| 欧美精品aaa| 亚洲无线码在线一区观看| 欧美日韩中文字幕| 91探花福利精品国产自产在线| 91欧美精品成人综合在线观看| 欧美亚洲激情在线| 国产精品扒开腿做爽爽爽视频| 91精品视频在线播放| 日本精品久久久| 久久影院免费观看| 国产日韩欧美在线| 中文字幕精品在线| 亚洲福利视频免费观看| 国产欧美久久久久久| xxxxxxxxx欧美| 原创国产精品91| 97在线视频观看| 日本高清视频一区| 亚洲欧洲一区二区三区在线观看| 国产午夜精品免费一区二区三区| 视频在线一区二区| 久久国产加勒比精品无码| 欧美在线观看www| 久久躁狠狠躁夜夜爽| 国产精品久久9| 国产啪精品视频| 精品久久久久久中文字幕大豆网| 国内精品久久久久久久| 欧美三级欧美成人高清www| 日韩视频精品在线| 日本三级韩国三级久久| 亚洲精品videossex少妇| 26uuu另类亚洲欧美日本一| 欧美xxxx18性欧美| 97久久精品国产| 亚洲精品免费网站| 久久久久久高潮国产精品视| 成人乱人伦精品视频在线观看| 亚洲一区二区三区四区在线播放| 不卡av在线播放| 国产成人精品国内自产拍免费看| 成人性生交大片免费看小说| 国产成人精品免高潮在线观看| 97久久精品视频| 亚洲最新在线视频| 国产在线播放91| 欧美乱人伦中文字幕在线| 久久男人的天堂| 精品久久久久久久中文字幕| 久久久97精品| 亚洲成人久久一区| 成人福利在线观看| 国产在线视频2019最新视频| 精品欧美国产一区二区三区| 激情懂色av一区av二区av| 欧美国产视频日韩| 中文字幕无线精品亚洲乱码一区| 精品国模在线视频| 国模精品系列视频| 国产精品久久久久久av福利软件| 亚洲成年网站在线观看| 国产精品96久久久久久又黄又硬| 自拍偷拍亚洲精品| 日韩一级裸体免费视频| 国产精品久久久一区| 日韩视频免费大全中文字幕| 亚洲影视中文字幕| 91国产视频在线播放| 亚洲精品wwww| 亚洲一区二区久久久久久| 日韩精品久久久久久福利| 57pao国产成人免费| 国产精品揄拍一区二区| 国产精品成人免费视频| 久久国内精品一国内精品| 国产主播欧美精品| 日本精品久久中文字幕佐佐木| 欧美另类极品videosbest最新版本| 精品国产自在精品国产浪潮| 欧美亚洲国产成人精品| 精品日韩中文字幕| 成人做爰www免费看视频网站| 97视频在线观看免费高清完整版在线观看| 91av中文字幕| 亚洲欧美国产一区二区三区| 一区二区三区四区在线观看视频| 国内精品伊人久久| 国语自产精品视频在线看一大j8| 日韩在线视频观看| 国产午夜精品麻豆| 国产精品扒开腿做爽爽爽视频| 国内揄拍国内精品少妇国语| 亚洲男人天堂2024| 国产日韩欧美91| 国产精品久久久久久久久免费| 日韩高清有码在线| zzjj国产精品一区二区| 亚洲欧美激情另类校园| 欧美日本高清一区| 国产精品第一区| 久久亚洲综合国产精品99麻豆精品福利| 亚洲bt欧美bt日本bt| 在线不卡国产精品| 91大神福利视频在线| 亚洲色图综合网| 欧美性猛交xxxxx水多| 色黄久久久久久| 欧美黑人一级爽快片淫片高清| 国产精品网址在线| 欧美成人性生活| 中文字幕亚洲欧美日韩2019| 成人国产精品av| 91久久精品美女高潮| 亚洲欧美一区二区三区久久| 欧美wwwwww| 97在线观看免费高清| 日本免费一区二区三区视频观看| 久久综合九色九九| 国产精品国内视频| www.美女亚洲精品| 国产一区二区三区在线看| 国产精品久久久久久久久久ktv| 成人福利网站在线观看11| 欧美高清在线视频观看不卡| 国产日韩精品一区二区| 一区二区三区回区在观看免费视频| 亚洲国产精品yw在线观看| 国产成人午夜视频网址| 欧美激情精品久久久久久蜜臀| 最新国产精品拍自在线播放| 久久久久成人网| 欧美黄色性视频| 麻豆国产精品va在线观看不卡| 久久91亚洲精品中文字幕奶水| 亚洲精品黄网在线观看| 国产精品激情av电影在线观看| 日本高清不卡的在线| 91超碰caoporn97人人| 91精品视频免费| 国产午夜精品美女视频明星a级| 中日韩午夜理伦电影免费| 成人免费xxxxx在线观看| 日韩中文字幕在线观看| 亚洲精品理论电影| 日韩中文字幕在线免费观看| 一本一本久久a久久精品牛牛影视| 51久久精品夜色国产麻豆| 国产69精品久久久久9| 国产一区欧美二区三区| 午夜精品久久久久久99热软件| 亚洲影影院av|