在Swift 4中关于JSON解析的简短思考

首先,将Codable定义为typealias Codable = Decodable&Encodable,我们采用两种必需的协议:

  1. 可解码 :解析JSON(获取响应)

–通过解码JSONData,我们将接收/读取数据

2. Encodable :生成JSON(响应后)

要将可编码 类型转换为Data

它适用于基本类型(Int,String和Float等),某些基础类型(数据,URL,日期等)以及数组,字典和可选参数(枚举)。

- NSData 
- NSString
- NSNumber
- UInt
- Int
- Float
- Double
- Bool
- NSDate
- NSArray
- NSDictionary

为什么?

  • 在我们的数据管理器中简化依赖关系
  • 将数据结构转换为JSON数据从未如此简单(hmmmm ..),允许开发人员将JSON数据存储到磁盘或将其编码为URLRequest的httpBody :)。

您可以编写一个使用外部来源的JSON或通过存根进行测试的应用。 这里的开始问题是您在应用程序中建模的概念的结构与JSON生产者建模的概念之间的不一致。 在您的应用中更改和使用JSON结构的一些示例:

  1. 使用CodingKey更改名称属性

2.通过手动编码和解码简化复杂的结构

3.使用嵌套数据(数组JSON内的数组)

对于1.,即使我们不必解析JSON表示形式的每个元素,我们也需要创建与JSONData中名称相同的属性,或者使用CodingKey重命名它们以直接存储基本示例。 到目前为止很简单!🤠🤠

  struct SurfBoard:可编码{ 
var品牌:字符串
var size:大小

枚举CodingKeys:字符串,CodingKey {
案例品牌=“名称”
大小
}
}

struct大小:可编码{
宽度:双
var高度:Double
}

注意:对于在NULL元素中声明的JSON属性,我们需要使用❓Optional镜像该实例。 这样,就不会因为输入错误或对JSON提供程序的保证产生误解而使数据无提示地丢失。

对于2.,在这种情况下,您可以提供自己的可编码和可解码的自定义逻辑od来定义自己的编码和解码逻辑。 您需要显式实现EncodableDecodable协议的encode(to 🙂init(from 🙂方法。

  struct SurfBoard { 
var品牌:字符串
var size:大小

枚举CodingKeys:字符串,CodingKey {
案例品牌=“名称”
情况宽度
情况高度
}
}

扩展程序SurfBoard:可编码{
func encode(编码器:编码器)抛出{
  var container = encoder.container(keyedBy:CodingKeys.self) 
尝试container.encode(brand,forKey:.title)
尝试container.encode(size.width,forKey:.width)
尝试container.encode(size.height,forKey:.height)
}
}

扩展程序SurfBoard:可解码{
init(来自解码器:解码器)抛出{
 让值=尝试解码器。容器(keyedBy:CodingKeys.self) 
品牌=尝试values.decode(String.self,forKey:.brand)
让width =试试values.decode(Double.self,forKey:.width)
让高度=尝试values.decode(Double.self,forKey:.height)
大小=大小(宽度:宽度,高度:高度)
}
}

您可以在这里获得不错的使用场景✅。

对于3.在这种情况下的嵌套数据,您需要解码和读取JSON。 可解码类型用作可以安全解码的中间类型。 它充当初始化程序中的数据源,用于您将在应用程序其余部分中使用的类型。

  //与外部JSON快速实现结构不兼容 
  struct SurfBoard { 
var品牌:字符串
var产品:[产品]

结构产品:可编码{
变量名称:字符串
var点:整数
var说明:字符串?
}
}

API返回的JSON包含的信息多于填充相应Swift类型所需的信息。

  //嵌套数组所需的快速结构 
  struct SurfBoardService:可解码{ 
让品牌:字符串
让过道:[过道]
 结构过道:可分解{ 
命名:字符串
让架子上:[架子]
 结构架:可分解的{ 
命名:字符串
让产品:SurfStore.Product
}
  } 
  } 

该扩展添加了一个带有SurfBoardService实例的初始化程序,并通过循环并丢弃过道和架子来消除不必要的嵌套。

要从外部数组中提取所需的数据,请编写一个与源JSON形状相似的类型,并将其标记为Decodable。 然后,在您将在应用程序其余部分中使用的类型上编写一个初始化程序,该初始化程序采用镜像源JSON的类型的实例。

 扩展SurfStore { 
init(来自服务:SurfBoardService){
品牌= service.brand
产品= []
用于服务通道。
用于在过道中的货架{
products.append(shelf.product)
}
  } 
  } 
  } 

在该说明上:

扩展只能提供便捷的初始化程序

  • 由于协议一致性而实现的初始化程序必须标记为required (在类上)。
  • required init只能在的主体内实现。
  • 由于没有继承,因此结构可以在扩展程序中具有初始化程序。

并最终阅读嵌套的JSON…

 让解码器= JSONDecoder() 
让serviceStores =试试decoder.decode([SurfBoardService] .self,来自:json)
让商店= serviceStores.compactMap {SurfBoard(from:$ 0)}
用于商店{
print(“ \(store.name)正在销售:”)
用于商店中的产品。products{
print(“ \ t \(product.name)(\(product.points)points)”)
如果让description = product.description {
打印(“ \ t \ t \(描述)”)
}
}
}

文档中的更多内容:合并来自不同深度的数据

如有任何疑问,请随时发表评论🙂 谢谢!

参考:

https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999

http://aplus.rs/2017/highly-maintainable-app-architecture/