【译】[SwiftUI 100 天] Cupcake Corner - part2
2020/4/7 23:01:28
本文主要是介绍【译】[SwiftUI 100 天] Cupcake Corner - part2,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
译自 Sending and receiving Codable data with URLSession and SwiftUI
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
用 URLSession 和 SwiftUI 发送和接收 Codable 数据
iOS 为我们提供了用于从网络发送和接收数据的内置工具,如果把它与Codable
支持结合使用,则可以将 Swift 对象转换为 JSON 进行发送,然后再接收回 JSON 并转换回 Swift 对象。更好的是,当请求完成时,我们可以立即将数据赋给 SwiftUI 视图中的属性,从而触发我们的用户界面更新。
为了演示这一点,我们要从 Apple 的 iTunes API 中加载一些示例音乐的 JSON 数据,然后显示在 SwiftUI 的List
中。Apple 的数据包含很多信息,我们要削减成两个类型:一个存储曲目 ID ,名称和所属专辑的Result
,和一个存储数组结果的Response
。
从下面的代码开始:
struct Response: Codable { var results: [Result] } struct Result: Codable { var trackId: Int var trackName: String var collectionName: String }复制代码
我们现在可以编写一个简单的ContentView
来显示结果数组:
struct ContentView: View { @State private var results = [Result]() var body: some View { List(results, id: \.trackId) { item in VStack(alignment: .leading) { Text(item.trackName) .font(.headline) Text(item.collectionName) } } } }复制代码
最开始不会显示任何内容,因为results
数组是空的。这里是我们进行网络调用的地方:我们将要求 iTunes API 给我们发送一个泰勒·斯威夫特的所有歌曲的清单,然后用JSONDecoder
把结果转换成一个Result
实例的数组。
为了便于理解,让我们分几个阶段进行编程。首先,是基本的方法 —— 把下面的存根添加到ContentView
结构体中:
func loadData() { }复制代码
我们希望在显示列表后立即执行它,因此,可以把下面这个 modifier 添加到List
:
.onAppear(perform: loadData)复制代码
在loadData()
内部,我们需要完成四个步骤:
- 创建我们要读取的 URL。
- 用
URLRequest
包装 URL,以便我们可以配置访问 URL 的方式。 - 基于这个 URL 请求创建并启动网络任务。
- 处理网络任务的结果。
我们将从 URL 开始,一步一步添加这些内容。这需要用到一个精确的格式:“itunes.apple.com”,后面跟着一系列参数 —— 如果你对 ”iTunes Search API“ 进行搜索,可以找到完整的参数集。在我们的案例中,我们要使用搜索词 “Taylor Swift” 和实体 “song”。现在,把下面的代码添加到loadData()
中:
guard let url = URL(string: "https://itunes.apple.com/search?term=taylor+swift&entity=song") else { print("Invalid URL") return }复制代码
接下来,我们需要把URL
包进一个URLRequest
中。再次说明,URLRequest
是我们添加不同的自定义项以控制 URL 加载方式的地方,但是在这里我们不需要任何内容,只有一行代码 —— 把它添加到loadData()
接下来的地方:
let request = URLRequest(url: url)复制代码
第三步是使用我们刚创建的URLRequest
创建并启动网络任务。当你第一次看到它的时候,它看起来像是一个很奇怪的方法,而且它有一个特别常见的“陷阱” —— 你可能会在长达几年的时间里一次又一次地犯下错误。
我先向你展示代码,然后解释它做了什么 —— 把下面的代码添加到loadData()
:
URLSession.shared.dataTask(with: request) { data, response, error in // 第四步 }.resume()复制代码
URLSession
是负责管理网络请求的 iOS 类。如果你愿意,可以创建自己的会话,但普遍的做法是使用 iOS 创建给我们使用的shared
会话 —— 除非你需要某些特定的行为,否则使用这个共享会话就可以了。
然后,我们在这个共享会话上调用dataTask(with:)
,它从URLRequest
中创建一个网络任务,并在任务完成时运行一个闭包。在我们的代码中,这是用拖尾闭包语法提供的,你可以看到它接受三个参数:
data
是从请求返回的数据。response
是数据的描述,它可能包含数据的类型,数据量,是否有状态码,等等。error
是出现的错误。
狡猾之处在于其中的一些属性是互斥的,我的意思是,如果发生error
,就不会设置data
,如果返回data
,则不会设置error
。之所以存在这种奇怪的状态,是因为URLSession
API 是在 Swift 出现之前创建的,没有更好的方法来表示这种二选一的状态。
注意到我们立即在任务上调用resume()
的方式了吗?这就是陷阱 —— 是你会一次又一次忘记的事情。没有它,这个请求将什么都不做,而你会盯着一个空白的屏幕。但是使用它,请求会立即开始,控制权移交到系统 —— 它会自动在后台运行,即使我们的方法结束,也不会被破坏。
当请求完成,无论成功与否,第四步会开始生效 —— 这就是数据任务中的闭包,它负责对数据或错误进行处理。在我们的案例中,我们会检查数据是否被设置,如果是则尝试将其解码为我们的Response
结构体的实例,因为这正是 iTunes API 发送回来的数据。我们实际上并不想要整个响应,而只是想要其中的结果数组,以便我们的List
将它们全部显示出来。
不过,这里还有另一个要点:URLSession
会在后台自动运行,这意味着它的完成关闭闭包也会运行在后台。所谓“后台”,是指技术上称为“后台线程”的东西 —— 与我们程序的其余部分同时运行的独立代码段。这意味着,网络请求甚至可以运行几秒钟,而不会阻断我们与 UI 的交互。
iOS 喜欢让它的所有用户界面工作都在“主线程”(程序启动时的线程)上完成。这个机制会断绝两段代码同时操作用户界面的可能性,因为如果所有与 UI 相关的工作都在主线程上进行,那么冲突不可能发生。
我们希望将视图的results
属性修改为通过 iTunes API 下载的内容,然后反过来更新我们的用户界面。在后台线程上做这件事可能也工作地很好,因为SwiftUI 超级聪明。但老实说,我们不必冒险。在后台获取数据,在后台解码 JSON,然后在主线程实际更新属性,是一个更好的主意。这样可以避免任何潜在的问题。
iOS 提供了一种非常特殊的方式,用来将工作发送到主线程:DispatchQueue.main.async()
。它接收一个执行工作的闭包,然后将其发送到主线程以执行。从名称中可以看出,实际上发生的事情是它被加入一个队列 —— 一个等待执行的长队伍。“async” 的部分是“异步”的缩写,表示我们自己的后台工作不会等待闭包的运行;我们只是把它添加到队列,然后继续后台的工作。
因此,用下面这段最后的代码替换// 第四步
的注释:
if let data = data { if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) { // 我们已经拿好数据 —— 回到主线程 DispatchQueue.main.async { // 更新我们的 UI self.results = decodedResponse.results } // 一切顺利,可以退出 return } } // 如果我们到了这里,说明出现问题 print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")复制代码
最后一行的print()
使用了可选链和空合运算符,如果存在错误则打印出错误,否则给出一个通用错误。
如果现在运行代码,你应该会在短暂的停顿后,看到 Taylor Swift 歌曲的列表 —— 考虑到最终结果的效果,我们的代码并不多。
在项目稍后的部分,我们将研究如何自定义URLRequest
,以便你可以发送Codable
数据,但目前已经足够了 —— 请将 ContentView.swift 还原回原始状态,以便我们开始工作。
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~
这篇关于【译】[SwiftUI 100 天] Cupcake Corner - part2的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值