Swift Basics #1
1. 控制台打印输出
在开发过程中,我们经常需要将信息输出到底部的控制台(Console),以便获取代码的反馈、检查运行状态或进行调试。在 Swift 中,使用 print() 函数来完成这一操作。
1 | // 直接打印字符串 |
2. 代码注释
注释是专门写给开发者自己或其他阅读代码的人看的,应用程序在编译和运行时会完全忽略这些内容。写注释不仅可以当作学习笔记,更是良好编程习惯的一部分。Swift 中有两种写注释的方法:
- 单行注释: 使用两个正斜杠
//。 - 多行注释: 以
/*开头,并以*/结尾。
1 | // 这是一个单行注释,通常用于简短的说明 |
3. 命名规范:驼峰命名法
在声明变量或常量时,不同的编程语言有不同的命名偏好。在 Swift 中,标准且被所有 Swift 开发者广泛接受的规范是驼峰命名法 (Camel Case)。 规则是:名称的第一个单词全部小写,之后紧跟的每一个单词的首字母都要大写。
1 | // ✅ 正确推荐:驼峰命名法 (Camel Case) |
Swift Basics #2
1. 字符串类型
字符串用于表示常规的文本内容。在 Swift 中,字符串必须被包裹在双引号中。如果没有双引号,编译器会将其误认为是代码的一部分从而报错。
1 | // 声明一个明确类型为 String 的常量 |
2. 布尔类型
布尔值用于表示逻辑上的“真”或“假”。它只能是两个值之一:true 或 false。在控制逻辑(例如“如果为真则执行某操作”)中非常有用。千万不要将布尔值用双引号包裹,否则它就变成了普通的字符串文本。
1 | // 声明一个明确类型为 Bool 的常量 |
3. 类型安全
Swift 是一门“类型安全”的编程语言。这意味着,如果你显式地告诉编译器某个变量或常量应该是什么类型,你就不能再给它赋予其他类型的值,否则代码将无法编译运行。这一特性可以极大程度地避免应用在运行中崩溃。一旦某个数据被定义为某种类型,它的类型就永远无法被更改。
1 | // ✅ 正确示范:类型匹配 |
4. 日期类型
Swift 内置了专门用于处理时间和日期的类型。它可以用来获取当前时间,或者记录应用中某个对象的创建和保存时间。
1 | // 声明一个日期类型,并使用 Date() 获取当前的时间 |
5. 数字类型
在 Swift 中,数字有很多种细分的类型。最常用的包括:
- Int: 整数,用于表示没有小数点的纯整数(例如 1, 2, 100)。
- Double: 双精度浮点数,支持小数点,常用于复杂的数学计算。
- CGFloat: 同样支持小数点,通常在处理用户界面(UI)元素(例如:屏幕边距为 15 像素,字体大小为 42)时使用。
1 | // Int 整数类型 |
Swift Basics #3
1. 常量与变量的区别
在 Swift 中,我们可以使用 let 和 var 来声明数据。
- 常量 (let): 一旦被赋值,它的值就永远不能再被改变。在编程中,我们应该尽可能多地使用常量,以保证代码的安全性和可预测性。
- 变量 (var): 它的值是可变的,在应用的运行周期内,你可以随时修改它的内容。只有当你明确知道这个数据未来需要被修改时,才应该使用变量。
1 | // 使用 let 声明常量,值不可修改 |
2. 类型的不可变性
虽然变量(var)的值可以被改变,但它的数据类型是永远不能被改变的。一旦一个变量被声明为某种特定类型(例如 Double),你赋予它的新值也必须是相同的类型,Swift 的类型安全机制会严格检查这一点。
1 | // 声明一个 Double 类型的变量 |
3. 基础条件判断语句
在代码中,我们经常需要根据某个条件是否成立来决定执行哪段代码。if 和 else 是最常用的条件判断语句。如果 if 后面的条件为真,则执行大括号里的代码;如果不为真,则执行 else 里的代码。
1 | var userIsPremium: Bool = false |
4. 布尔值判断的简写形式
在判断布尔值时,Swift 开发者通常会使用更简洁的写法,而不是写出完整的 == true 或 == false。
- 检查是否为
true,可以直接写变量名。 - 检查是否为
false,可以在变量名前面加一个英文感叹号!(表示“非”)。
1 | var isPremium: Bool = true |
Swift Basics #4
1. 数学运算符与简写语法
Swift 支持基础的加(+)、减(-)、乘(*)、除(/)等算术运算。为了简化代码,Swift 提供了组合赋值运算符,用来直接在原变量的基础上进行加减乘除并重新赋值。
1 | var likeCount: Double = 5.0 |
2. 运算优先级
与我们在数学课上学到的规则一样,Swift 中的代码运算也严格遵守“先乘除,后加减”的优先级顺序(PEMDAS 规则)。你可以使用括号 () 来改变运算的执行顺序。
1 | var mathResult: Double = 0.0 |
3. 比较运算符
比较运算符常用于 if 语句中,用来对比两个数据的大小或验证是否相等。常用运算符包括:等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)和小于等于(<=)。
1 | let viewCount = 100 |
4. 逻辑运算符
当我们需要在同一个 if 语句中同时检查多个条件时,可以使用逻辑运算符来组合它们:
- 逻辑与 (
&&): 只有当符号两边的条件都为真时,整体才为真。 - 逻辑或 (
||): 只要符号两边的条件中有一个为真,整体就为真。
1 | let comments = 10 |
5. 多重条件判断语句
如果单个 if 和 else 无法覆盖所有的情况,我们可以使用 else if 来进行多重条件链式判断。程序会从上往下依次检查,一旦遇到满足条件的区块,就会立刻执行它并跳出整个判断链。
1 | let currentLikes = 30 |
Swift Basics #5
1. 基础函数的定义与调用
使用 func 关键字可以定义一个函数。函数内部的代码(大括号 {} 里的内容)只有在函数被明确调用时才会执行。函数内部定义的变量是私有的(局部变量),无法被函数外部直接访问,这有助于保护数据安全。
1 | // 定义一个基础函数 |
2. 函数的返回值
有时候我们需要函数执行完某个逻辑后,把结果交还给我们。这时可以在函数声明的括号后面使用箭头 ->,并指定返回数据的类型(比如 String 或 Bool)。请注意,一旦指明了返回类型,函数内部就必须通过 return 关键字返回对应类型的值,否则编译器会报错。
1 | // 定义一个返回 String 类型的函数 |
3. 向函数传递参数
为了让函数更灵活,我们可以在调用函数时向其“投递”数据。这些数据被称为参数。我们需要在函数声明的括号 () 内定义参数的名称和类型。
1 | // 定义一个需要接收两个 Bool 类型参数的函数 |
4. 控制流:If 与 Guard 语句
在函数内部控制逻辑走向时,if 和 guard 是最常用的两种方式:
if语句:如果是真,则进入大括号内部执行代码。guard语句:用于“提前拦截”。确保某件事为真,如果为假,则进入else大括号内执行代码并立刻return(退出整个函数),不再执行后续逻辑。
1 | func checkTitle(title: String) -> Bool { |
5. 计算属性
如果在某个逻辑块中,我们不需要从外部传入任何参数就能得到一个结果,我们通常可以使用计算属性(Calculated Variables)来替代没有参数的函数。它的写法就像声明一个普通的变量,但在后面跟上一对大括号 {},每次调用这个变量时,大括号里的代码都会被重新执行一遍。
1 | let numberOne = 5 |
Swift Basics #6
1. 什么是可选类型
在 Swift 中,常规的数据类型(如 Bool、String)必须始终有一个确定的值。而可选类型代表这个变量“可能有一个具体的值,也可能什么都没有(nil)”。 在数据类型后面加上一个问号 ? 即可将其声明为可选类型。
1 | // 常规布尔值,只能是 true 或 false |
2. 空值合并运算符提供默认值
当我们试图把一个“可选类型”赋值给一个“非可选类型”时,编译器会报错。最简单的解决办法是使用空值合并运算符 ??。它的含义是:“如果左边有值,就使用左边的值;如果是 nil,就使用右边提供的默认值。”
1 | var optionalName: String? = nil |
3. 使用 if let 安全解包
在函数中,我们往往需要确认某个数据真的存在后才执行对应的逻辑。if let 是一种安全的解包方式:“如果这个可选类型有值,就把这个值赋给一个全新的局部常量,并进入大括号内执行代码。”
1 | func printUserStatus(userIsPremium: Bool?) { |
(注:在较新的 Swift 版本中,如果变量名相同,你可以简写为 if let userIsPremium { ... })
4. 使用 guard let 提前拦截解包
guard let 与 if let 的作用类似,但逻辑走向相反。它的核心思想是:“确保这个可选类型有值,否则立刻退出(return)当前函数。” 这种方式可以避免代码出现层层嵌套(“死亡金字塔”),让主要逻辑处于函数的最外层,更加清晰明了。
1 | func setupUserProfile(userName: String?) { |
5. 可选链的使用
有时我们需要访问可选类型内部的某个属性或方法。为了避免繁琐的 if let 嵌套,Swift 提供了可选链操作符 ?.。它的逻辑是:“如果该对象不是 nil,就继续往后执行/获取属性;如果该对象是 nil,立刻停止,并返回一个 nil。”
1 | var optionalUsername: String? = "Nick" |
6. 强制解包的危险性
在某些特殊情况下,开发者可以使用感叹号 ! 对可选类型进行强制解包。这相当于告诉编译器:“我百分之百确定它里面有值,不用管安全机制了”。 强烈警告: 如果你进行了强制解包,但该变量在运行时的实际值却是 nil,你的 App 将会直接崩溃(Crash)。在日常开发与面试中,除非极特殊情况,永远不要轻易使用强制解包。
1 | var optionalUsername: String? = nil |
Swift Basics #7
1. 创建元组并从函数中返回
如果我们想让函数返回多个值,可以在函数的返回值类型声明中使用圆括号 () 将多个类型包裹起来。在函数内部 return 时,同样使用圆括号将对应的数据打包返回。
1 | var username: String = "Hello" |
2. 通过索引访问元组的数据
当我们获取到一个元组后,如果元组内的元素没有具体的名字,Swift 会自动为它们分配基于零的索引(类似于数组)。我们可以使用 . 加上数字索引(如 .0, .1)来提取里面具体的数据。
1 | let infoOne = getUserInfo() |
3. 为元组的参数命名
使用数字索引(.0, .1)在代码量变大时会变得非常难以阅读,因为你很难记住 0 代表什么。为了提升代码可读性,我们可以在声明元组类型时,为每一个元素指定一个明确的名称。
1 | // 在返回值声明中,为元组的每一个元素命名 |
4. 将元组作为参数传递给其他函数
元组不仅可以作为函数的返回值,它本身也是一种数据类型。这意味着我们可以将整个元组作为一个单独的参数,传递给其他的函数。这在需要同时传递一组相关联的数据时非常有用。
1 | // 定义一个包含三个数据的元组返回函数 |
Swift Basics #8
1. 对象的生命周期与内存分配
当我们创建一个对象时,实际上是在调用它的“初始化器(Init)”,这会在内存中为其分配空间(Allocate)。当我们在应用中不再需要这个对象时,系统会调用“反初始化器(Deinit)”,将其从内存中释放(Deallocate)。
1 | class AppScreen { |
2. 自动引用计数
Swift 使用一种名为 自动引用计数 (ARC, Automatic Reference Counting) 的机制来管理内存。你可以把它理解为一个计数器:每当有一个新的类对象进入内存,计数器加 1;销毁一个对象,计数器减 1。内存中驻留的对象越多,App 运行越慢。因此,优秀的原则是:仅在需要时创建对象,一旦不需要立刻将其销毁。
1 | class User { |
3. 内存的两种类型:栈与堆
iOS 设备是一个多线程(Multi-threaded)环境。你可以把线程想象成一个个独立的引擎。
- 栈 (Stack): 每个引擎(线程)都有自己独立的栈。栈速度非常快,内存占用小。大部分基础数据(如 String、Bool、Int、Struct、Enum)都存储在栈中。它们不计入 ARC。
- 堆 (Heap): 所有的引擎(线程)共享同一个堆。因为需要跨线程同步,堆的速度相对较慢,内存占用大。类(Class)和函数都存储在堆中。只有堆中的对象才会计入 ARC。
1 | // 存储在【栈】中的类型,速度极快 |
4. 值类型与引用类型的区别
这也是结构体(Struct)和类(Class)最本质的区别:
- 值类型 (Value Types): 当你修改栈中的数据(如 Struct)时,系统实际上是复制(Copy) 了一份旧数据,粘贴(Paste) 出来一份新副本,并赋上新值。
- 引用类型 (Reference Types): 堆中的数据(如 Class)是通过“指针”引用的。当你修改它时,你是在直接修改内存中那份唯一的数据本身,而不是创建一个新副本。
1 | struct StructData { var count = 0 } |
5. 结构体与类的使用场景
在实际开发中,我们应该如何选择呢?视频中给出了一个生动的比喻:
- 类就像“教室”: 教室本身不怎么移动,它很稳定,我们在教室内部执行各种动作(如管理数据、网络请求)。对应的开发概念是:Manager、ViewModel、DataService 等核心组件。
- 结构体就像“试卷”: 试卷被老师复印了很多份,在学生之间传来传去。对应的开发概念是:Data Model(如单纯的用户信息、文章信息)。它们只是一小块数据,在 App 的各个屏幕间被频繁传递。
1 | // 这是一个单纯的数据模型,像“试卷”一样被传来传去,使用 struct |
Swift Basics #9
1. 隐式初始化器
在 Swift 中,当你创建一个结构体并定义了若干属性后,你不需要手动编写 init(初始化)函数。Swift 编译器会在背后自动为你生成一个包含所有属性的隐式初始化器。
1 | struct Quiz { |
2. 自定义初始化器与默认值
虽然有隐式初始化器,但如果你想为某些属性提供默认值,你可以手动编写 init 函数。这样在创建对象时,拥有默认值的参数就可以被省略。
1 | struct CustomQuiz { |
3. 不可变结构体与“修改”方式
如果结构体内部的所有属性都是使用 let 声明的常量,那么这个结构体就是不可变的(Immutable)。这是非常推荐的编程习惯。想要“修改”这种结构体的数据,标准做法是在结构体内部写一个方法,返回一个包含了新数据和旧数据拷贝的全新结构体实例。
1 | struct ImmutableUser { |
4. 可变结构体与 Mutating 关键字
如果结构体内部使用了 var 声明变量,代表它是可变的。但是,由于结构体是值类型,Swift 默认不允许你在结构体自己的方法中直接修改自己的属性。为了打破这个限制,你必须在方法前面加上 mutating 关键字,明确告诉编译器:“这个方法将会改变结构体自身的数据”。
1 | struct MutableUser { |
5. 私有设置器控制访问权限
如果我们把属性公开为 var,外部的任何代码都可以随意篡改它(例如 user2.isPremium = true),这会导致数据来源混乱。为了保证安全,我们可以使用 private(set)。它的作用是:外部代码可以读取这个值,但只能通过结构体内部提供的 mutating 方法来修改它。
1 | struct SecureUser { |
Swift Basics #10
1. 枚举的基础概念与语法
使用 enum 关键字可以定义一个枚举。在枚举内部,使用 case 关键字来列出所有可能的选项。这就相当于你创造了一种新的数据类型,它的值只能是你列出的这几个选项之一。
1 | // 定义一个名为 OperatingSystem (操作系统) 的枚举类型 |
2. 为什么需要枚举
在没有枚举时,开发者经常使用纯字符串(String)来表示状态或选项。这种做法极其危险,因为开发者可能会拼写错误,或者传入未预期的值,而编译器无法提前发现这种错误。枚举通过“强制选项”完美解决了这个问题。
1 | // ❌ 危险的做法:使用纯字符串 |
3. 枚举与分支语句的结合
枚举最完美的搭档是 switch 语句。由于枚举的选项是有限且已知的,当你使用 switch 检查枚举时,Swift 编译器会强制你处理所有可能的 case。这种“穷举检查”可以确保你不会遗漏任何一种情况。
1 | let currentSystem = OperatingSystem.macOS |
4. 枚举的原始值
你可以为枚举的每一个 case 绑定一个底层的基础值(称为原始值),通常是 String 或 Int。通过在定义枚举时指定类型,并在选项后赋值,你就可以随时通过 .rawValue 属性来提取这个底层数据。
1 | // 声明该枚举的原始值类型为 String |
5. 通过原始值初始化枚举
除了提取原始值,如果你手头只有一个普通的数据(比如从网络请求拿到的字符串),你也可以尝试用它来“转换”生成一个枚举对象。因为传入的值可能不匹配任何选项,所以这个初始化方法返回的是一个可选类型(Optional)。
1 | let databaseString = "明亮模式" |
Swift Basics #11
1. 类的定义与手动初始化
类的基本声明语法与结构体非常相似,使用 class 关键字。但最显著的编码区别在于:类没有隐式初始化器。如果类内部的属性没有默认值,你必须手动编写 init 函数来完成初始化操作,否则编译器会直接报错。
1 | class ScreenViewModel { |
2. 修改内部数据无需关键字
在结构体中,如果要在自身的方法内修改属性,必须在方法前加上 mutating 关键字。但是,类天生就是在原地修改内存数据的,因此在类内部修改自身属性时,完全不需要任何特殊的关键字。
1 | class UserDataManager { |
3. 引用类型的本质与数据共享
类是引用类型,这意味着它在传递时传递的是“内存指针”。如果你把一个类实例赋值给另一个变量,你其实并没有复制数据,而是让两个变量指向了内存中的同一个对象。改动其中一个,另一个也会同步改变。
1 | class Car { |
4. 常量实例与可变属性
这是类与结构体在行为上极其反直觉的一点!如果你使用 let(常量)来声明一个结构体实例,那么它内部的所有数据都将被完全锁死,无法修改。 但是,如果你使用 let 声明一个类实例,只要类内部的属性是用 var 定义的,你依然可以自由修改这些属性的值。这是因为 let 仅仅锁死了“这个常量不能再指向另一个类实例”,但并没有锁死该内存地址里存储的数据本身。
1 | class NetworkService { |
Swift Basics #12
1. 默认权限 (Public / Internal)
当你声明一个变量或函数,并且不在前面加任何权限修饰符时,在绝大多数日常开发中,你可以把它视作是公开的(Public)。这意味着在类的外部,你可以随意读取(Get)并且随意修改(Set)这个变量。
注意:虽然这最方便,但在优秀的架构设计中,这往往被认为是“过于公开”的,不够安全。
1 | class MovieManager { |
2. 私有权限 (Private)
在声明前面加上 private 关键字,意味着这个属性或方法只能在这个类(或结构体)的大括号内部被访问。外部代码既不能读取它,也不能修改它。这通常用于隐藏类内部的计算细节或敏感数据。
1 | class SecureManager { |
3. 私有设置器 (Private Set)
这是在实际应用架构(如 MVVM)中最常用、也是最被推荐的最佳实践。使用 private(set) 意味着:对外部开放读取权限(Public Get),但修改权限依然是私有的(Private Set)。 外部如果想要修改这个值,只能通过调用类提供的方法来实现。这样类就能完全掌控数据被修改的规则和时机。
1 | class AdvancedManager { |
Swift Basics #13
1. 数组的定义与初始化
数组是一种有序的列表。在 Swift 中,我们使用方括号 [] 来包裹数组的内容,并通过 [数据类型] 来声明数组的类型。数组中存放的所有元素都必须是同一种类型。
1 | // 声明一个明确类型为 String 数组的变量 |
2. 统计元素个数与获取首尾元素
当你拿到一个数组时,你可以随时查看它里面包含多少个元素。同时,你也可以快速获取排在第一位或最后一位的元素。由于数组有可能是空的(里面没有任何数据),所以获取首尾元素返回的其实是可选类型(Optional)。
1 | let fruitsArray = ["Apple", "Orange", "Banana"] |
3. 通过索引访问数据与“越界崩溃”
数组的计算(Count)是从 1 开始的,但是数组的索引(Index)是从 0 开始的。也就是说,第一个元素的索引是 0,第二个是 1,以此类推。 严重警告: 如果你尝试通过索引直接访问一个不存在的位置(例如数组只有 3 个元素,你却去拿索引为 10 的元素),你的 App 会立刻崩溃(Crash)。
1 | let fruitsArray = ["Apple", "Orange", "Banana"] |
4. 动态修改数组元素
只要数组是被声明为变量(var)的,我们就可以在代码运行期间随意地在任意位置添加或移除数据。修改数组实际上也是在变相地“变异(Mutating)”原有的结构。
1 | var myFruits = ["Apple", "Orange"] |
5. 存放自定义对象
数组不仅可以存放系统自带的字符串或数字,它也可以用来装载你自己定义的结构体(Struct)或类(Class)。这是构建真实 App 最常见的数据流转方式。
1 | struct ProductModel { |
6. 集合与数组的核心区别
集合(Sets) 的语法看起来和数组很像,但它有两个决定性的区别:
- 元素必须唯一: 集合里绝对不允许出现两个一模一样的数据(会自动去重)。
- 完全无序: 集合没有“第一项”或“第二项”的概念,每次打印出来的顺序可能都不一样,因此你无法通过像
[0]这样的索引去访问它。
1 | // 数组:允许重复,严格保持存入时的顺序 |
Swift Basics #14
1. 字典的定义与初始化
在声明字典时,我们需要在方括号内同时指定“键(Key)”的类型和“值(Value)”的类型,中间用冒号 : 隔开。字典中的“键”必须是唯一的,绝对不能重复。
1 | // 声明一个键为 String 类型,值为 Bool 类型的字典 |
2. 安全的数据访问机制(不会越界崩溃)
在上一节课中提到,如果访问了数组中不存在的索引,App 会直接崩溃。但字典非常安全:当你尝试通过一个 Key 去获取数据时,如果这个 Key 不存在,它只会平静地返回 nil。 正因如此,字典通过 Key 提取出来的值永远是可选类型(Optional)。
1 | let fruitsDict: [String: Bool] = ["Apple": true] |
3. 动态添加与更新数据
因为字典是无序的,所以它没有 append(追加到末尾)或 insert(插入到指定位置)的概念。要想添加或更新数据,你只需要直接通过对应的 Key 进行赋值即可。如果 Key 已经存在,旧数据会被覆盖;如果 Key 不存在,就会新增一组键值对。
1 | var myDict: [String: String] = [ |
4. 移除字典中的数据
除了添加数据,我们也可以随时从字典中精准剔除不需要的键值对。使用 removeValue(forKey:) 方法即可完成操作。
1 | var myDict: [String: String] = [ |
5. 结合自定义模型的高级用法
在真实的项目中,我们经常从后端服务器获取包含唯一 ID 的数据模型。将这些唯一 ID 作为“键”,将数据模型本身作为“值”存入字典,可以实现极速的数据查询。
1 | struct PostModel { |
6. 数组与字典的选择场景
使用数组(Arrays): 当数据的顺序至关重要时(比如要在屏幕的列表中从上到下按序展示信息),必须使用数组。
使用字典(Dictionaries): 当数据顺序无所谓,但你需要通过唯一标识符(ID)进行极速查找,且不想担心越界崩溃问题时,字典是最佳选择。
Swift Basics #15
1. 使用数字范围进行基础循环
你可以设定一个数字范围,让一段代码精准执行指定的次数。在 Swift 中,通常使用半开区间 0..<上限 来进行循环,这非常符合编程中从 0 开始计数的习惯。
1 | // 循环 50 次,数字从 0 一直变化到 49 |
2. 直接遍历数组中的元素
当你已经有一个数组时,不需要关心它有多长,直接使用 for item in array 的语法,系统会自动把数组里的每一项依次提取出来供你使用。
1 | let myStringArray: [String] = ["Alpha", "Beta", "Gamma"] |
3. 在循环中筛选与重组数据
我们经常在循环体内部嵌套 if 逻辑判断语句,用来检查当前元素是否符合特定条件。如果符合,我们可以把它提取出来存入另一个全新的数组中,从而实现数据的“手动筛选”。
1 | struct Lesson { |
4. 同时获取索引与元素的枚举循环
普通的遍历只能拿到元素本身。但有时候我们在循环时,既需要拿到“元素”,又需要知道它是数组里的“第几个(索引)”。这时候可以使用 .enumerated() 方法,它会同时返回索引和对应的元素。
1 | let animals = ["Dog", "Cat", "Bird"] |
5. 循环的流程控制指令
在循环过程中,我们可以根据特定条件随时干预循环的走向,最常用的两个指令是 break 和 continue:
- 终止指令 (break): 直接砸碎并跳出整个循环。一旦触发,循环彻底结束,后面的所有元素都不再遍历。
- 跳过指令 (continue): 仅仅放弃当前这一次遍历中剩下的代码,直接跳到下一个元素继续执行后续的循环。
1 | let numbers = [0, 1, 2, 3, 4] |
Swift Basics #16
1. 使用 Filter 筛选数据
当我们需要根据某个条件,从一个大数组中挑出符合条件的部分元素,并组成一个新的数组时,使用 .filter 是最简单的方法。它会在背后自动遍历数组,你只需要告诉它“什么样的元素可以被保留(返回 true)”。
1 | struct DatabaseUser { |
2. 使用 Sort 对数据进行排序
如果数组中的元素是自定义的结构体或类,系统并不知道该按什么规则排序(比如是按字母排,还是按价格排?)。此时,我们需要使用 .sorted 方法,并提供一个排序规则:当你拿出任意两个元素(比如 user1 和 user2)进行对比时,谁应该排在前面。
1 | struct OrderedUser { |
3. 使用 Map 映射转换数据类型
这是开发中最常用的魔法之一!当我们有一个复杂的对象数组(例如包含姓名、年龄、VIP 状态的用户模型数组),但我们仅仅只需要他们的名字,想要得到一个纯字符串数组([String])时,就可以使用 .map。它会遍历原数组,将每一个元素“转换”为你想要的形态,并返回一个全新的数组。
1 | struct UserProfile { |