如何使用Codable在Swift 4中下载和解析Google Place JSON响应

作者的注释: 对我来说重要的是,本教程应尽可能易于遵循。 如果您有帮助实现此目标的建议,请直接与我联系。

对于新的iOS开发人员而言,网络可能是最令人困惑和困难的主题之一。

好消息! 在Swift 4中,下载和解析JSON比以往任何时候都容易,而且您可以使用清晰易懂的100%本机代码来做到这一点!

您可以通过以下方法从Google地方信息下载和解析JSON。 一旦您了解了这一点,我相信您将能够从任何地方的任何JSON下载和解析信息。

JSON基础:

  • JSON响应由key:value对组成。
  • 将始终为字符串类型。
  • 的类型可以是:字符串,数字,布尔值,数组,对象或null。
  • 数组用方括号([])表示。
  • 对象用大括号({})表示。
  1. 看一下您的源中的样本JSON。 在本练习中,我们的来源是Google地方信息。 识别应用程序所需的JSON字段是关键,因此您可以使对象简洁明了。 对于本练习,我想展示如何解析来自各种不同JSON情况的数据,除了标准键值关系外,还包括数组和嵌套对象。 这是示例JSON中的一项:

2. 创建一系列符合Codable的结构。 这些结构将保存我们从JSON读取的值。

可编码结构的基本结构:

  • 符合编码
  • 包含一个或多个常量,这些常量将保存从JSON读取的值
  • 包含符合String&Coding Key的枚举。 枚举将在JSON键和您的常量之间建立连接。

我建议将这些结构放在自己的Swift文件中。 为了我们的目的,我们将该文件称为ResponseModels.swift。

GooglePlacesResponse结构

//一种。 我们正在使结构符合Codable。

// b。 我们将把结果保存在Place类型的对象数组中。

//C。 我们使用枚举来确保Codable知道从JSON读取的适当密钥。 在这种情况下,我们的results数组对应于JSON中的键“结果” (图1,一级)

放置结构

//一种。 完成Place结构后,我们将创建Location结构。

// b。 在我们的JSON中,有些地方有开放时间,有些没有。 因此,我们将此对象标记为可选。

如果您指示Codable搜索不存在的密钥,并且您的常量未标记为可选,则您将无法成功解码JSON并且不会收到任何结果。

//C。 在这里,我们将遍历JSON中的数组,并返回一个或多个自定义结构的值。

// d。 在这种情况下,我们的常量名与JSON中的键名不匹配。

位置和LatLong结构

如果您注意到了,我们实际关心的两个值,即纬度和经度的Doubles,位于JSON的第4级上。 由于我不会在项目的其他任何地方重复使用Location或LatLong结构,因此我将把Location结构和LatLong结构嵌套在Place结构中。

//一种。 我们的LatLong结构嵌套在Location结构中。

OpenNow结构和照片结构

//一种。 即使OpenNow是可选值,我们的打开常量也不是可选的。

这就是我们的结构! 由于我不打算在项目的其他任何地方使用OpenNow或PhotoInfo数据对象,因此我将所有内容嵌套在Place结构中。

这是完成的ResponseModels.swift文件:

好的,这是很多工作! 恭喜! 现在,我们将从网络代码开始。

3.为您的客户请求创建一个协议 (该代码先请求然后下载JSON)。 使用协议将为您(开发人员)提供一个很好的路线图,以了解您的客户端请求类将实际执行的操作。

首先,创建一个新的.swift文件。 我建议调用文件GoogleClient.swift。

其次,在下面写下您的协议:

注意: googlePlacesKey包含在我们的协议中,因为如果没有有效的密钥,Google地方信息将拒绝您的请求。 在这里获取您自己的密钥。

另外,由于我们的getGooglePlacesData函数使用CLLocation,因此我们必须授予对CoreLocation库的文件访问权限。 为此,请将以下语句放在保存该协议的.swift文件的顶部:

 导入CoreLocation 

2. 创建一个符合您的GoogleClientRequest协议的类。 有两个步骤。

首先,要告诉编译器您的类将符合您的协议,则在声明该类后必须插入一个冒号,后跟协议的名称。

其次,您必须使新声明的类符合您的协议。 为此,请在新声明的类中实现协议中包含的变量和函数。

3. 编写您的实现代码。 除了填写密钥和联网呼叫之外,我还要添加两件事:URLSession和用于定义Google URL的辅助函数。

URL会话将获取我们的Google URL并请求我们的数据。 将此代码添加到我们的GoogleClient类中:

此帮助程序功能将抽象化我们将发送给Google的URL的创建。 此示例中的URL将为Google提供一个位置和关键字,并返回最接近所提供位置的位置。 要了解有关如何自定义Google URL以根据我们在此使用的参数以外的参数提供结果的更多信息,请阅读此内容。

将此googlePlacesDataUrl函数添加到我们的GoogleClient类中。

现在,让我们填写我们的getGooglePlacesData函数的实现:

// 一种。 使用我们的帮助程序功能定义将发送给Google的URL。

// b。 使用我们的URL运行我们的dataTask。 dataTask将与我们的URL指向的服务器联系,询问它一些信息,并返回数据或错误。 (注意:为简单起见,我们将忽略URLResponse)

// C。 检查我们是否有错误。 如果发生错误,则我们拥有所需的JSON数据的可能性为零。 因此,我们打印错误并返回该函数。

注意: 在正式版应用中,您将向用户添加警报,告知他们的网络请求失败,但是我们不在此做。

// d。 在这里,我们链接了一个警卫声明。 首先,我们检查是否存在responseData。 如果responseData存在,我们会将数据传递到JSONDecoder中。 JSONDecoder.decode是一个可能引发错误的函数,因此我们用try?进行标记,这意味着如果解码器无法读取JSON,它将返回nil,我们的代码将直接进入// e

// e。 如果执行此语句,则很可能收到了数据,但无法完全解码它。 因此,我们用一个空的数据集调用完成处理程序并返回该函数。 JSON值很可能与结构中的值不匹配。 请仔细检查。

// F。 如果一切都按计划进行,我们的代码将使用解码后的数据调用完成处理程序。

// G。 如果由于某种原因我们的任务被中断,此命令将继续执行。

我们整个GoogleClient.swift文件

4.在ViewController.swift中调用函数

通过抽象化数据模型以及网络代码,您已经完成了所有繁重的工作。 现在剩下的就是在ViewController中调用函数了!

我们要做的第一件事是设置我们需要的常量和变量:

//一种。 我们必须有一个GoogleClient类的实例,因为该类是执行网络调用的类! 我在这里使用惰性变量,因为惰性变量在需要之前不会实例化,从而节省了宝贵的内存!

// b。 为简单起见,我已将马萨诸塞州波士顿的硬代码编码为currentLocation(我住的地方!)。 如果您想要更动态的应用程序,请研究如何利用Apple的CLLocationManagerDelegate方法获取当前位置。

//C。 我已经在星巴克中硬编码了我们的搜索参数。 面对现实,到处都有星巴克,因此将其用作我们的测试用例应该可以给我们带来很多结果。 对于更动态的应用程序,您可能需要创建一个UITextField供用户输入其搜索参数。

//一种。 我将搜索半径设置为2500米,相当于〜1.55英里。 如果您所在位置的约1.55英里范围内没有星巴克,请增加此数字。

现在, 让我们扩展ViewController并添加我们的网络调用。

现在添加最后的修饰,让我们(最终!)调用fetchGoogleData函数并打印出结果数据。

这是您的最终ViewController.swift文件:

我添加了我们的函数调用以及一个辅助函数,该函数在收到结果时会打印我们的数据。

//一种。 我们的函数调用。

// b。 Helper函数,将前五个Place结果打印到每个可消化的String中。

而已! 恭喜,您现在有了下载和解析可在Internet上找到的任何JSON的工具!

源代码可以在这里找到。

干杯!