> 软件编程 > Swift >
Swift JSON教程:使用JSON 2017-05-12 17:27 出处:清屏网 人气:
2017-1-15 更新说明:本教程由 Luke Parham 更新为 Xcode 8.2 和 Swift 3。原文作者是 Attila Hegedüs。
JavaScript Object Notation,简称 JSON,是一种常用的和 web 服务进行数据传输的方式。它易于使用和阅读,因此使用者众多。
以下列 JSON 为例:
[ { "person": { "name": "Dani", "age": "24" } }, { "person": { "name": "Ray", "age": "70" } } ]在 O-C 中,解析这段 JSON 非常简单:
NSArray *json = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:nil]; NSString *age = json[0][@"person"][@"age"]; NSLog(@"Dani's age is %@", age);在 Swift 中,要解析这段 JSON 就相当麻烦了,因为 Swift 有 optional 和类型安全的限制:
var json: [Any]? do { json = try JSONSerialization.jsonObject(with: data) } catch { print(error) } guard let item = json?.first as? [String: Any], let person = item["person"] as? [String: Any], let age = person["age"] as? Int else { return }由于 guard 语句的存在,我们摆脱了厄运金字塔代码,但仍然需要些大量重复的代码才能访问 JSON 字符串中的数据。
在这篇 Swift JSON 教程里,我们一开始会用 Swift 的原生方法来解析 JSON——不使用任何第三方库。这实际上是苹果推荐的做法,因为 Swift 内置的工具在大部分场景下都够我们用了。
但是,就像每个人都会偶尔发出叛逆的声音,你也可以阅读本教程的下半部分,学习如何用 Gloss 框架节省你的时间。
注意:Gloss 只是众多 JSON 框架之一,但它却是一个好的设计模式的例子,我们会很好地证明这一点。
我们会用这两种方式对一个 JSON 文件进行解析,这个文件列出了美国 App 商店中上榜“25 个最流行的 app”的应用。
开始因为学习 JSON 并不需要用户界面,因此我们所有的练习都是在 playground 中进行的。请在 这里 下载开始项目。
打开 Swift.playground 。
注意:你可能发现 playground 的项目导航器是关闭的。如果是这样,请用 command+1 打开它。
开始项目中有几个源文件和资源文件,这是为了将你的注意力集中在用 Swift 解析 JSON 的主题上来。看一下项目结构,以了解大概的内容:
Resources 文件夹中包含了你要解析的示例 JSON 文件。
Sources 文件夹中包含在主 playground 代码中能够调用的其它 Swift 源文件。将这些源文件放在 Sources 文件夹中是为了让你的 playground 干净、可读行更高。
你可以浏览一下 playground 中内容,再继续后面的内容!
原生 Swift JSON 解析看完示例的 JSON 文件之后,我们可以来解析它并打印出排名第一的 app 是什么!
使用 optional 的初始化方法首先,打开 App.swift。里面有一个简单的模型对象,定义了一个初始化方法,使用一个名字和一个链接作为初始化参数。
这个 JSON 文件的 entry 下面有一个对象数组,每个对象都代表了一个 App 对象。
根据这个结构,我们要在原来的初始化方法下面新增一个 optional 的初始化方法。
//1 public init?(json: [String: Any]) { //2 guard let container = json["im:name"] as? [String: Any], let name = container["label"] as? String, let id = json["id"] as? [String: Any], let link = id["label"] as? String else { return nil } //3 self.name = name self.link = link }这个初始化方法使用一个 [String:Any] 字典作为参数,这个字典用 JSON 数据来构造。这是可以的,有效的 JSON 要么是数组要么是单个值,但是我们已经确定它就是一个字典。
然后,用 guard-let 语法去解析 JSON,取出其中的 name 和 link 值。
最后,如果所有值都不为空,则填充模型对象的属性并返回模型。
创建好模型之后,在项目导航器中点击 TopApps-Starter,打开主 playground 文件。
首先,在 getTopAppsDataFromFileWithSuccess 方法的 success 块中添加 guard 语句:
guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { PlaygroundPage.current.finishExecution() }这里,我们用 jsonObject(with:options:) 方法将 JSON 字符串转换为 JSON 对象。
然后,我们进行第一步解析,获得代表第一个 App 的 JSON 对象。
guard let feed = json?["feed"] as? [String: Any], let apps = feed["entry"] as? [[String: Any]], let firstApp = apps.first else { PlaygroundPage.current.finishExecution() }这一步,我们首先取得最外层的 feed 对象,它的 entry 键中包含了 app 数组。
最后,调用我们早先写好的 optional 的初始化函数获得排名第一的 app:
let app = App(json: firstApp) print(app ?? "Failed to initialize")运行 app,控制台输出如下:
App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")好了—— “Game of War – Fire Age” 就是在这个 JSON 文件中排名第一的 app。
使用能够抛出异常的初始化方法在初始化失败时返回一个 nil 而不是实例对象,并不能告诉我们到底发生了什么错误。
打开 App.swift ,定义一个错误枚举。
enum SerializationError: Error { case missing(String) }