第52天 项目 10 第四部分
我们在这里开展的每个新项目,都会先单独向你介绍新概念,然后再结合实际应用场景进行讲解。这样做的目的是,在不同情境下两次展示同一内容,能帮助你更深刻地将其存入长期记忆。
但如今,我们的应用已经完成,是时候进入长期学习过程中另一个重要环节了:检验你的记忆成果,并通过一些挑战帮助你进一步提升。无论你是否愿意,这一步都至关重要——正如宇航员约翰·杨曾经说过的:“进步最大的敌人,是自以为懂了的错觉。”
请相信我:确定自己理解某件事,远胜于认为自己理解它。这就是我不断向你强调基础知识的原因:我希望你对Form的使用熟悉到几乎能自己编写这门课程的程度;我希望你看到Codable时,能准确明白它的含义以及背后的工作原理,再也不会觉得它带有某种“魔力”。
我们在这里打下的所有基础,都将陪伴你多年。这意味着,你在此之上构建的一切——未来学到的知识、创造的成果——都不会建立在对某段内容一知半解的基础上,而是能让你拥有真正持久的信心。
今天,你应当完成第10个项目的总结章节,完成相关复习,然后攻克所有三个挑战。
- 纸杯蛋糕店(Cupcake Corner):总结
- 第10个项目复习:纸杯蛋糕店(Cupcake Corner)
纸杯蛋糕店(Cupcake Corner):总结
作者:Paul Hudson 2024年4月11日
希望这个项目能让你学会如何运用已掌握的技能——SwiftUI中的表单(Form)、选择器(Picker)、步进器(Stepper)和导航功能——构建一个能将用户所有数据发送到服务器并处理响应的应用。
你现在可能还没意识到,这个项目中学到的技能,对绝大多数iOS开发者来说都是最重要的:收集用户数据、发送到服务器并处理响应,这一流程可能占据了现有半数以上非简单应用的核心功能。诚然,发送的数据内容以及更新用户界面(UI)的方式会有很大差异,但背后的核心概念是完全相同的。
复习所学内容
任何人都能看完一个教程,但要记住所学内容,就需要付出实际努力了。我的职责是确保你能从这些教程中收获尽可能多的知识,完成后面的练习题可以帮助你检验学习成果。
挑战
学习编程最好的方法之一,就是尽可能多地自己编写代码。因此,我为你准备了三种扩展这个应用的方式,确保你能完全理解其中的原理。
- 目前,我们的地址字段只要包含任何内容(即便是纯空格),就会被视为有效。请改进验证逻辑,确保纯空格字符串被判定为无效。
- 如果调用
placeOrder()失败(例如没有网络连接),请向用户显示一条提示性弹窗。要测试这一点,可以尝试注释掉代码中的request.httpMethod = "POST"这一行,这样就能强制让请求失败。 - 这是一个更有挑战性的任务:尝试更新
Order类,使其能将用户的配送地址等数据保存到UserDefaults中。这需要一些思考,因为@AppStorage在此处无法使用,而且你会发现,使用 getter 和 setter 会对Codable支持造成问题。你能找到一个折中方案吗?
【练习题】纸杯蛋糕店(Cupcake Corner)
问题1/12:以下哪些表述是正确的?
- 选项1:如果一个Swift结构体仅由符合
Codable协议的属性组成,那么整个结构体本身也可以符合Codable协议。 - 选项2:当
disabled()修饰符的条件为false时,它所附加的视图将停止响应用户交互。
问题2/12:以下哪些表述是正确的?
- 选项1:我们可以创建一个枚举来为某个类型定义特定的编码键(coding keys),但该枚举的名称必须是
CodingKeys。 - 选项2:异步函数在完成工作的过程中可以暂停(sleep)。
问题3/12:以下哪些表述是正确的?
- 选项1:Swift的数组使用泛型(generics)。
- 选项2:我们可以使用“或”(OR)操作符检查两个布尔值中是否有一个或两个为
true,例如booleanA OR booleanB。
问题4/12:以下哪些表述是正确的?
- 选项1:
@Observable宏仅适用于类(class)。 - 选项2:
disabled()修饰符可以读取任何类型的属性,但不能与方法(method)一起使用。
问题5/12:以下哪些表述是正确的?
- 选项1:如果异步函数不会暂停(sleep),调用时就不需要使用
await。 - 选项2:通过字符串创建
URL时,返回的是可选类型(optional)的URL。
问题6/12:以下哪些表述是正确的?
- 选项1:字符串(String)、整数(Int)和布尔值(Bool)本身已符合
Codable协议。 - 选项2:
URLRequest可以使用共享队列(shared queue)从互联网获取数据。
问题7/12:以下哪些表述是正确的?
- 选项1:
CodingKey协议允许我们通过枚举案例(enum case)列出想要归档(archive)和反归档(unarchive)的属性。 - 选项2:所有使用
@Observable的类都会自动符合Codable协议。
问题8/12:以下哪些表述是正确的?
- 选项1:我们可以在任何时候使用
Task { … }创建一个新任务。 - 选项2:MIME类型是由喜欢假装自己被困在箱子里的无声戏剧演员发明的。
问题9/12:以下哪些表述是正确的?
- 选项1:通常更倾向于使用
URLSession的shared属性,而不是自己创建一个新的会话(session)。 - 选项2:如果可以选择,采用“字符串类型化”(stringly typed)的API总是更优的选择。
问题10/12:以下哪些表述是正确的?
- 选项1:HTTP的GET请求用于读取数据,POST请求用于写入数据。
- 选项2:HTTP的POST请求用于读取数据,GET请求用于写入数据。
问题11/12:以下哪些表述是正确的?
- 选项1:初始化器(initializer)必须始终接受与类中属性匹配的参数。
- 选项2:当
URLSession的下载任务完成时,会返回下载的数据以及所有附加的元数据(metadata)。
问题12/12:以下哪些表述是正确的?
- 选项1:异步函数调用总会有一定时间的暂停(sleep)。
- 选项2:
Codable协议实际上是Encodable协议和Decodable协议的组合。