第一次尝试译文,如果有错误谢谢指正。这里面的例子有的是我自己通过XCTest测试的. KennyBest!
译文地址:https://developer.apple.com/swift/blog/?id=37
如果你的APP和web程序进行交互,那么从服务器返回的数据大都是JSON格式。你可以使用Foundation
框架中的JSONSerialization
类将JSON数据转化为Swift
类型数据,例如Dictionary
、Array
、String
、Number
、Bool。然而,你并不能确定从服务器获取到的JSON
值或者结构,正确地转化模型对象变成难题。这篇博文正是描述一些当你使用JSON
交互时可采用的途径。
<! – more –>
从JSON中取数据
JSONSerializtion
类提供了jsonObject(with:options:)
类方法返回数据类型为Any
数据,如果当数据不能被解析时抛出一个错误。
|
|
尽管有效的JSON
可能只包含单个数据,从服务器响应的数据通常以数组或者字典作为最外层模型进行编码。你可以在if
或guard
语法中使用可选绑定和as?
或as!
类型指定操作符以常量的形式取出来已知类型的数据。通常指定为[String : Any]
来从JSON
数据中获取字典Dictionary
,指定为[Any]
获得数组Array
(或者更明确元素类型的数组,像[String]
)。 借助下标语法存取Subscript
和枚举元素类型可选绑定后你可以通过key值摘取字典数据或者通过下标取得数组数据。
|
|
Swift
的built-in
语言特性使得不需要导入额外的库或框架,就可以轻松安全地摘取和使用由Foundation
框架中的API解码的JSON
数据。
利用从JSON获取的数据创建Model
大部分APP遵循MVC设计模式,在一个类的定义中将JSON
数据转化为对象变得很平常。
例如,当你写一个提供当地餐馆搜索结果的APP时,你可能实现一个Restaurant
模型,在这个模型中定义一个接受JSON
数据的构造函数和一个请求餐馆列表的类方法。
从下面这个类中考虑
|
|
一个餐馆有String
类型name
属性,元组
类型coordinates
属性以及Set
类型Meal
属性。
服务器响应数据格式:
写一个可选的JSON构造函数
为了从JSON
数据转化为一个餐馆对象,写一个带有Any
类型参数的构造函数,旨在从JSON数据中拿取数据且转变为属性。
|
|
如果你的APP与多个web服务进行交互,并且返回的数据不单一,那么就考虑实现多个构造函数来匹配所有可能的呈现方式。
在上面的例子中,通过可选绑定和as?
类型指定来将JSON数据映射到模型的属性上。
写一个带错误管理的JSON构造函数
前一个例子实现了一个可选构造器,当反序列化失败时返回nil。另外,你也可以定义一个遵守Error
协议的类型和实现一个可在反序列化失败时返回错误的构造器。
|
|
这里,Restaurtant
类里面声明了一个嵌套的SerializationError
类型,定义了关联属性缺失和无效属性两种错误情况。这种抛出错误的构造器强于在序列化错误返回nil的构造器,可以抛出明确的交互错误。这次构造函数同样可以验证数据的合法性。
写获取数据源的类方法
一个web应用终端通常在单个JSON
响应中返回多个数据源。比如/search
终端可能返回0或多个匹配查询参数的餐馆,下面一段数据展示这种情况:
|
|
你可以在Restaurant
结构体中创建一个类方法,将查询条件正确地转化为
请求参数,并向服务器发送一个请求。这段代码同时也响应了服务器请求,解析JSON
数据,把从results
数组中获取的每一个字典转化为Restaurant
对象,并在完成处理时自动返回。
|
|
在viewController中,当搜索条件发生变化时调用这个方法。
|
|
用这种方式分离管理为获取餐馆数据提供了便利,即使具体实现发生改变。
映射中的映射
在不同的系统中对相同数据的呈现方式转换对于写软件来说是单调、必要的任务。
因为这些呈现方式的结构十分相似,这可能会创建高层级抽象过程去自动在不同呈现间映射。举例来说,一个类可能会为了自动初始化一个模型,利用Swift
映射API去定义一种JSON
key值和类里面的属性名称之间的映射关系。例如Mirror
。
然而,我们会发现这些抽象过程性质在Swift
语言特性的常规使用场景上并没有提供客观的收益,反而在调试问题和处理额外情景上带来了更多的困扰。通过上面的例子,构造器不但从JSON
数据中获取和映射数据,还构造了混合数据类型和执行范围有效性验证。
为了实现这些所有的功能,基于映射途径可能会有较大长度。 对于我们的APP来说,评估效率时应该考虑这些。一些重复代码的消耗比使用错误的映射过程更有意义。