1 print 打印

swift
print (1, 2, 3, 4, 5) // 1 2 3 4 5
print (1, 2, 3, 4, 5, separator: "_") // 1_2_3_4_5
print ("My name is Jake.", terminator:"--")
print ("My age is 18.")
// My name is Jake.--My age is 18.
let name = "小王"
print("你好\(name)")
2 值类型 vs 引用类型
在 Swift 中,值类型 和引用类型 的核心区别在于:赋值或传递时,是复制内容还是共享同一个实例。
值类型 struct, enum, tuple(元祖)
-
值类型赋值给var、let或者给函数传参,是直接将所有内容拷贝一份
-
类似于对文件进行copy、paste操作,产生了全新的文件副本。属于深拷贝(deep copy)
引用类型 class, closure (闭包)
-
引用赋值给var、let或者给函数传参,是将内存地址拷贝一份
-
类似于制作一个文件的替身(快捷方式、链接),指向的是同一个文件。属于浅拷贝(shallow copy )
2.1 值类型赋值操作
swift
// 1 字符串
var s1 = "Jack"
var s2 = s1
s2. append ("_Rose")
print(s1) // Jack
print(s2) // Jack_Rose
swift
// 3 字典
var d1 = ["max": 10, "min" : 2]
var d2 = d1
d1["other"] = 7
d2 ["max"] = 12
print (d1) // ["other": 7, "max": 10, "min": 2]
print (d2) // ["max": 12, "min": 2]
swift
// 结构体 struct
struct Point {
var x: Int
var y: Int
}
var point1 = Point(x: 0, y: 0)
var point2 = point1 // 复制
point2.x = 10
print(point1.x) // 0(未被修改)
print(point2.x) // 10
口 在Swift标准库中,为了提升性能,String、Array、Dictionary、Set采取了Copy On Write的技术
口 比如仅当有"写"操作时,才会真正执行拷贝操作
口 对于标准库值类型的赋值操作,Swift 能确保最佳性能,所有没必要为了保证最佳性能来避免赋值建
口 建议:不需要修改的,尽量定义成let
2.2 引用类型赋值
swift
// 引用类型 - class
class Dog {
var name: String
init(name: String) { self.name = name }
}
let dog1 = Dog(name: "Buddy")
let dog2 = dog1 // 引用同一个对象
dog2.name = "Max"
print(dog1.name) // "Max"(被修改了)
print(dog2.name) // "Max"
15 函数定义在结构体, 类, 枚举中
一般把定义在枚举、结构体、类内部的函数,叫做方法
swift
class Size {
var width = 10
var height = 10
func show() {
print("width=| (width), height=\ (height)")
}
}
let s = Size()
s.show() // width=10, height=10
swift
struct Point {
var x = 10
var y = 10
func show() {
print("x=\ (x), y=\ (y)")
}
}
let p = Point ()
p.show()// ×=10,y=10
swift
enum PokerFace : String {
case spades = "黑桃", hearts = "红心", diamonds = "方片", clubs = "草花"
func show() {
print("face is \(rawValue)")
}
}
let pf = PokerFace.hearts
pf.show() // face is "红心"
方法占用对象的内存么?
口不占用
口方法的本质就是函数
口方法、函数都存放在代码段
4 字面量
一句话总结:字面量就是你直接写在代码里的"原始数据",不需要计算就能知道它是什么。
swift
// 字面量
let a = 10 // 10 是整数字面量
let b = 3.14 // 3.14 是浮点数字面量
let c = "Hello" // "Hello" 是字符串字面量
let d = true // true 是布尔字面量
let e = [1, 2, 3] // [1, 2, 3] 是数组字面量
let f = ["a": 1] // ["a": 1] 是字典字面量
swift
// 非字面量
let y = x + 2 // x + 2 不是字面量(是表达式)
let z = Int("10") // Int("10") 不是字面量(是函数调用)
5 区间运算
swift
// 1 闭区间运算符
let names = ["a", "b","c","d"]
for i in 0...3 {
print(names[i]) //a b c d
}
swift
// 2 半开区间运算符
for i in 0..<2 { // a..<b 代表 a<=值<b
print(name[i]) //a b
}
swift
// 3 单侧区间
names[2...] // 2~3 2 到 最大
names[...2] // 0~2 最小 到 2
names[..<2] // 0~1 最小 到 小于2
swift
// 4 区间变量
letrange = ...5 // -负无穷 到5
print(range) // PartialRangeThrough<Int>(upperBound: 5)
print(range.contains(7)) // false
print(range.contains(-99)) // true
swift
// 5区间可以是Int 也可以是字符串
let range = "a"..."z"// 打印字符串, 注意没指定类型就是字符串 从字符 a 到 z
print(range.contains("f")) // true
print(range.contains("F")) // false
6 switch语句
swift
// 1 区别于 oc 可以不写break
let number = 1
switch number {
case 1:
print("1")
break
case 2 :
print("2")
// break 可以不写,不会贯穿
default:
print("都不是")
}
swift
// 2 fallthrough 可以实现贯穿效果
var number = 1
switch number {
case 1:
print("'number is 1")
fallthrough
case 2:
print ("number is 2")
default:
print ("number is other")
}
// number is 1
// number is 2
swift
// 3 区间匹配
let count = 62
switch count {
case 0:
print("none")
case 1..<5:
print("a few")
case 5..<12:
print("several")
case 12..<100:
print ("dozens of")
case 100..<1000:
print("hundreds of")
default:
print("many")
}
// dozens of
swift
// 4 元祖匹配
let point = (1, 1)
switch point {
case (0, 0):
print ("the origin")
case (_, 0):
print("on the *-axis")
case (0, _):
print("on the y-axis")
case (-2...2 ,-2...2):
print("inside the box")
default:
print ("outside of the box")
}
// inside the box
swift
// 5 符合条件
let string = "Jack"
switch string {
case "Jack":
print("jack---")
fallthrough
case "Rose":
print ("Right person")
default:
break
}
// jack---
// Right person
let string = "Jack"
switch string {
case "Jack", "Rose": // 或
print ("Right person")
default:
break
}
// Right person
let character: Character = "a"
switch character {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// The letter A
swift
// 6 值绑定
enum Result {
case success(String, Int)
case failure(String)
}
let result = Result.success("登录成功", 200)
switch result {
case .success(let message, let code):
print("成功: \(message), 代码: \(code)")
case .failure(let error):
print("失败: \(error)")
}
swift
// 7 where 条件语句
let point = (1, -1)
switch point {
case let (x, y) where x == y:
print("on the line x == y")
case let (x, y) where x == -y:
print("on the line x == -y") // on the line x == -y
case let (x, y) :
print("(\(x), \(y)) is just some arbitrary point")
}
swift
// 7.1 将所有正数加起来
var numbers = [10,20,-10,-20,30,-30]
var sum = 0
for num in numbers where num > 0{ // 使用where来过滤num
sum += num
}
print(sum) // 60
7 标签语句
swift
// 普通 for循环的 break
for i in 1...3 {
for j in 1...3 {
if j == 2 {
break // 只跳出内层循环,外层继续
}
print("(\(i),\(j))")
}
}
// 输出:(1,1) (2,1) (3,1)
// break 是跳出本次循环 当i = 1 j= 2 是后跳出i=1这循环, i = 2/3 同
swift
// 添加标签的for循环 break
outer: for i in 1...3 {
for j in 1...3 {
if j == 2 {
break outer // 跳出整个外层循环
}
print("(\(i),\(j))")
}
}
// 输出:(1,1)
// 遇到 j==2 后完全结束,不再继续
// 添加标签作用, 直接跳出整个循环 break outer
8 函数
swift
// 函数定义
func funcname(形参) -> returntype
{
Statement1
Statement2
......
Statement N
return parameters
}
8.1 函数隐式返回
swift
// 函数隐式返回:如果一个函数体是单行表达式,可以省略 return 关键字,函数会自动返回该表达式的值。
func sum(v1: Int, v2: Int) - Int {
v1 + V2
}
sum(v1: 10, v2: 20) // 30
8.2 函数多返回值
swift
// 通过元祖 实现函数多返回值
func calculate(v1: Int, V2: Int) -> (sum: Int, difference: Int, average: Int) {
let sum = v1 + v2
return (sum, v1 - v2, sum >> 1)
}
// sum >> 1 除以2的1次幂
let result = calculate (v1: 20, v2: 10)
result. sum // 30
result.difference // 10
result.average // 15
8.3 省略形参标签
swift
// 使用下划线, 省略形参标签
func sum(_ v1: Int, _ v2: Int) -> Int {
v1 + v2
}
sum (10, 20)
8.4 函数默认值
swift
// 参数可以有默认值
func check(name: String = "nobody", age: Int, job: String = "none") {
print("name=\ (name), age=\ (age), job=\(job)")
}
check(name: "Jack", age: 20, job: "Doctor") // name=Jack, age=20, job=Doctor
check(name: "Rose", age: 18) // name=Rose, age=18, job=none
checklage: 10, job: "Batman"') // name=nobody, age=10, job=Batman
check(age: 15) // name=nobody, age=15,
8.5 函数可变参数
swift
// 可变参数
func sum _ numbers: Int...) →> Int {
var total = 0
for number in numbers {
total += number
}
return total
}
sum (10, 20, 30, 40) // 100
swift
// 一个函数最多只能有1个可变参数
// 紧跟在可变参数后面的参数不能省略参数标签
// 参数string不能省略标签
func test_ numbers: Int..., string: String, _ other: String) {
}
test (10, 20, 30, string: "Jack", "Rose")
8.6 输入输出函数 inout
- 可以用inout定义一个输入输出参数:可以在函数内部修改外部实参的值
swift
// 可变参数不能标记为inout
// inout参数不能有默认值
// inout参数的本质是地址传递(引用传递)
func swapValues(_ V1: inout Int,- v2: inout Int){
let tmp = v1
v1 = v2
v2 = tmp
}
var num1 = 10
var num2 = 20
swapValues (&num1, &num2)
swift
func swapValues (_ v1: inout Int, _ V2: inout Int) {
(v1, V2) = (v2, v1)
}
8.7 内联函数 @line
内联函数 debug默认未开启, release开启

以下函数不会触发内联函数
- 1 函数体比较长
- 2 包含递归调用
- 3 包含动态派发(oc调用)
swift
// 内联函数
func test(){
print("哈哈")
}
test() // 开启内联函数, 即 test() 等价于调用 这句print("哈哈")
// 调用函数时候直接执行了函数的函数体
// 这样减少了调用函数的开销,开辟和回收栈空间
swift
// 永远不会被内联(即使开启了编译器优化) @inline(never)
@inline(never)func test(){
print("test")
}
// 开启编译器优化后,即使代码很长,也会被内联(递归调用函数、动态派发的函数除外)@inline(__always)
@inline(__always)func test(){
print ("test")
}
8.8 函数类型
每一个函数都是有类型的,函数类型由形式参数类型、返回值类型组成
swift
func test(){}
func test ()-> Void {}
func test ()->(){}
// 这三个等价
swift
func sum(a: Int, b: Int) -> Int {
a + b
}
//(Int,Int)-> Int
swift
// 定义变量
var fn:(Int,Int) -> Int = sumfn(2,3)
// 5,调用时不需要参数标签
8.9 函数类型作为函数参数
swift
func sum(v1: Int,v2: Int)-> Int {
v1 + v2
}
func difference(v1: Int, v2: Int) -> Int {
v1 - v2
}
func printResult(_ mathFn: (Int, Int) - Int, _ a: Int, _ b: Int) {
print("Result: \(mathFn(a, b) )")
}
printResult(sum, 5, 2) // Result: 7
printResult (difference, 5, 2) // Result: 3
8.9 函数类型作为函数返回值
swift
func next|_ input: Int) → Int {
input + 1
}
func previous (_ input: Int) -> Int {
input - 1
}
func forward(_ forward: Bool) -> (Int) -> Int { // 看第一个尖号
forward ? next : previous
}
forward (true) (3) // 4
forward (false)(3) // 2
8.10 嵌套函数
将函数定义在函数内部
swift
func forward (
forward: Bool) - (Int) - Int {
func next(_ input: Int) - Int {
input + 1
}
func previous (_ input: Int) → Int {
input - 1
}
return forward ? next : previous
}
forward(true) (3) // 4
forward (false) (3) // 2
9 别名typealise
typealias 用来给类型起别名
swift
// 起别名
typealias Date = (year: Int, month: Int, day: Int)
func test (_ date: Date) {
print (date.0)
print (date.year)
}
test((2011,9,10))
swift
// 按照Swift标准库的定义,Void 就是空元组()
public typealias Void = ()
swift
typealias Date = (year: Int, month: Int, day: Int)
func test (_ date: Date) {
print (date.1)
print (date.year)
}
test((2021,9,10))
// 9
// 2021
9 枚举 (值类型)
1 枚举未指定类型, 则没有rawValue原始值, 也不能设置默认值
2 枚举指定类型, 会生成rawValue原始值
3 枚举关联值,主要场景是当模型用
4 内部声明计算属性,不能存储属性
5 枚举内能定义方法
6 枚举能继承协议 解析模型
9.1 基本用法
swift
enum Direction {
case east
case south
case west
case north
}
swift
// 错误使用! ! !
let dir = Direction() // 报错!!! 没有可访问的初始化器()
swift
// 正确使用
let east = Direction.east // 枚举名访问
print("\(east)----\(type(of: east))") // east----Direction
switch east {
case .east:
print("西风")
case .south:
print("南风")
case .west:
print("西风")
case .north:
print("北风")
}
9.2 原始值 rawValue
swift
// 隐式原始值
enum grade: String {
case perfect
case great
case good
case bad
}
print(grade.perfect.rawValue) // perfect
print(type(of: grade.perfect.rawValue)) // String
swift
// 指定类型, 生成原始值
enum grade: String {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
print(grade.perfect.rawValue) // A
print(grade.great.rawValue) // B
print(grade.good.rawValue) // C
print(grade.bad.rawValue) // D
swift
// 枚举未指定类型, 则没有rawValue原始值, 也不能设置默认值
enum grade {
case perfect = "sss" // 报错!!! 未指定枚举类型,不能设置默认值
case great
case good
case bad
}
9.3 关联值
swift
// 通过枚举关联值 保存网络请求数据
enum NetworkResponse {
case success(Data)
case failure(String)
}
func fetchUserInfo(userId: Int, completion: @escaping (NetworkResponse) -> Void) {
let url = URL(string: "https://api.example.com/user/\(userId)")!
URLSession.shared.dataTask(with: url) { data, response, error in
// 统一处理所有错误
if let error = error {
completion(.failure(error.localizedDescription))
return
}
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200,
let data = data else {
completion(.failure("请求失败"))
return
}
completion(.success(data))
}.resume()
}
// 使用
fetchUserInfo(userId: 123) { response in
switch response {
case .success(let data):
print("成功")
// 解析 data
case .failure(let error):
print("失败: \(error)")
if error == "请求失败" {
// 可能需要登录或其他处理
}
}
}
swift
// 通过结构体模型 保存网络请求数据
struct NetworkResponse {
let isSuccess: Bool
let data: Data?
let errorMessage: String?
}
func fetchUserInfo(userId: Int, completion: @escaping (NetworkResponse) -> Void) {
let url = URL(string: "https://api.example.com/user/\(userId)")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(NetworkResponse(isSuccess: false, data: nil, errorMessage: error.localizedDescription))
return
}
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200,
let data = data else {
completion(NetworkResponse(isSuccess: false, data: nil, errorMessage: "请求失败"))
return
}
completion(NetworkResponse(isSuccess: true, data: data, errorMessage: nil))
}.resume()
}
// 使用
fetchUserInfo(userId: 123) { response in
if response.isSuccess, let data = response.data {
print("成功")
// 解析 data
} else {
print("失败: \(response.errorMessage ?? "未知错误")")
if response.errorMessage == "请求失败" {
// 可能需要登录或其他处理
}
}
}
9.4 遵守协议 ?????
swift
// 6 枚举遵守协议
enum XXManType: RawRepresentable {
// RawRepresentable(原始可代表)
// 这个协议需要自己实现一个 init?(rawValue: String)方法 和一个 rawValue属性
// 作用通过rawValue值创建枚举, 枚举为可选类型, 创建失败为nil
// 场景: 字典转模型
case boy(title: String)
case girl(title: String)
// 初始化方法, 通过rawValue 创建
typealias RawValue = String
init?(rawValue: String) {
switch rawValue {
case "boy":
self = .boy(title: "boy")
case "girl":
self = .girl(title: "girl")
default:
self = .boy(title: "boy")
}
}
// rawValue 计算属性
var rawValue: String {
switch self {
case .boy(let title):
return title
case .girl(let title):
return title
}
}
}
// 字典转模型
class swiftModel: Mappable {
var name: String = ""
var age: String = ""
var category: XXCertificateType = .marriage(title: "") // 对应一个枚举
var man: XXManType = .boy(title: "") // 枚举变量
// mappable 需实现方法
required init?(map: Map) {
}
// mappable 需实现方法
func mapping(map: Map) {
name <- map["name"]
age <- map["age"] // 赋值给字符串
category <- map["category"] // 赋值给枚举
man <- map["man"] // 赋值给枚举
// man字符串, 通过rawValue赋值生成一个枚举
}
}
10 可选项
*可选项 Optional: 是用来表示一个值可能存在,也可能不存在(nil)的类型;
包含普通可选 T?, 隐式解包 T!
-
普通可选: 必须手动解包(
!、if let、??等), 安全, 强制处理 nil -
隐式解包: 部分场景自动解包,部分需手动 ,方便, 但有崩溃风险 (隐式解包完全兼容, 普通可选的所有操作)
ps:
1 可选项: 就是定义个可以赋值为nil的类型; 2 隐式解包: 就是为解包提供方便, 可以隐式的解包, 但是仅仅部分场景
10.1 可选项声明
swift
class ViewController: UIViewController {
// MARK: - 属性声明
// 普通可选
var userName: String?
var userAge: Int?
var userAvatar: UIImage?
var database: Database! // 依赖注入,一定会初始化
var config: Config! // 依赖注入,一定会初始化
var curTitle: String!
// 隐式解包(常见于IBOulet)
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var nameTextField: UITextField!
10.2 可选项赋值
swift
// MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
// 给普通可选赋值
userName = "张三"
userAge = 25
// 给隐式解包赋值(模拟初始化)
database = Database()
config = Config()
curTitle = "哈哈"
// 调用各种使用场景
demoOptionalUsage()
demoImplicitUsage()
}
10.3 普通可选使用
swift
// MARK: - 1. 普通可选的各种使用方式
func demoOptionalUsage() {
print("=== 普通可选示例 ===")
// 方式1:可选链 (Optional Chaining)
let nameLength = userName?.count // Int?
// 方式2:强制解包 (Forced Unwrapping) - 危险
if userName != nil {
let name = userName! // String
}
// 方式3:可选绑定 (Optional Binding)
if let name = userName { // String
print("可选绑定: \(name), 长度: \(name.count)") // name只能在内部用
}
// 方式4:空合并运算符 (Nil Coalescing)
let displayName = userName ?? "匿名用户" // String
print("空合并: \(displayName)")
// 方式5:guard let (提前退出)
guard let age = userAge else { // age是Int
return
}
print("年龄: \(age)") // age可以在外面用
// 方式6:map方法
let greeting = userName.map { "你好, \($0)" } // String?
print("map结果: \(greeting ?? "")")
// 普通可选总结:
// 普通可选项 使用需要解包后才能用
// 解包方法: 强制解包, 可选绑定(guard 绑定), 空合并运算符
}
10.4 隐式解包使用
swift
// MARK: - 2. 隐式解包的各种使用方式
func demoImplicitUsage() {
print("\n=== 隐式解包示例 ===")
// 方式1:直接访问(当作非可选使用)- 有崩溃风险
let labelText = titleLabel.text // String? (text本身是可选)
print("直接访问: \(labelText ?? "")") // titleLabel 为 UILabel?
// 方式2:可选链(也可以用,返回可选)
let textLength = titleLabel?.text?.count // Int?
print("可选链访问: \(textLength ?? 0)")
// 方式3:可选绑定(推荐安全使用)
if let db = database { // db是Database类型
db.connect()
}
// 方式4:空合并运算符
let dbName = database?.name ?? "默认数据库" // String
print("数据库名: \(dbName)")
// 方式5:guard let
guard let config = config else {
return
}
config.load()
// 触发隐式解包场景
// 场景1
print("\(type(of: database))") // Database?
let name = database.name // String
let sumstring = database.name + "史蒂芬" // String
// 场景2
print("\(type(of: curTitle))-") // String?
let aa = curTitle + "aa"
print("\(type(of: aa))-") //String
}
// MARK: - 辅助类
class Database {
var name: String = "主数据库"
func connect() {
print("数据库已连接")
}
}
class Config {
func load() {
print("配置已加载")
}
}
11 guard语句/ 卫兵语句
-
1 当guard语句的条件为 false 时, 执行大括号里面的
-
2 当guard语句的条件为 true 时, 就会跳过guard语句
-
3 guard语句特别适合 "提前退出"
swift
guard 条件 else {
// do something....
退出当前作用域
return
}
当使用guard语句进行可选项绑定时,绑定的常量(let)、变量(var)也能在外层作用域中使用
swift
func login(_ info: [String : String]) {
guard let username = info ["username"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
print("用户名:\(username)", "密码:\(password)", "登陆ing")
12 结构体 (值类型)
1 成员可以不设置默认初始值
2 编译器会自动生成初始化方法
3 如果自定义初始化方法,会覆盖系统创建的初始化方法
4 初始化需确保所有成员都有值
在Swift 标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分
比如Bool、Int、Double、String、Array、 Dictionary等常见类型都是结构
swift
struct Date {
var year: Int // 可以设置初始值
var month: Int
var day: Int
}
var date = Date(year: 2019,month: 6, day: 23)// 初始化需确保,所有成员都有值
12.1 自定义初始化器
一旦在定义结构体时自定义了初始化器,编译器就不会再帮它自动生成其他初始化器
swift
// 确保所有成员都初始化
struct Point {
var x: Int
var y: Int
}
var p1 = Point(x: 10, y: 10)
// var p2 = Point (y: 10)
// var p3 = Point(x: 10)
// var p4 = Point()
swift
// 编译器生成初始化器
struct Point {
var x: Int = 0
var y: Int = 0
// init(x: Int, y: Int) {
// self.x = x
// self.y = y
// }
}
var p1 = Point(x: 10, y: 10)
var p2 = Point (y: 10)
var p3 = Point(x: 10)
var p4 = Point()
swift
// 自定义初始化器 覆盖了自动生成的初始化器
struct Point {
var x: Int = 0
var y: Int = 0
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
var p1 = Point(x: 10, y: 10)
// var p2 = Point (y: 10)
// var p3 = Point(x: 10)
// var p4 = Point()
13 类 (引用类型)
1 成员须设置默认初始值 (或声明时候默认,或写在自定义初始化方法里)
2 会自动创建无参数初始化方法 class()
3 如果自定义初始化方法,会覆盖系统创建初始化方法
4 初始化需保证所有成员都有值
13.1 类 初始化成员
swift
// 声明 直接默认初始值
class Man {
var name: String = ""
var height:String = ""
var age: Int = 0
}
swift
// 初始化器 默认初始值
class Man {
var name: String
var height:String
var age: Int
init(name: String = "", height: String = "", age: Int = 0) {
self.name = name
self.height = height
self.age = age
}
// or
init(name: String , height: String, age: Int) {
self.name = ""
self.height = ""
self.age = 0
}
}
14 闭包表达式
闭包表达式, 就是函数, 匿名函数
swift
// 闭包表达式 定义
{(参数, 参数) -> 返回值类型 in
函数体代码
}
// 注意函数体 没有return
// 闭包 必须指明, 或靠上下文推断
14.1 函数&闭包对比
swift
// 函数
func sum(_ v1: Int, _v2: Int) -> Int {
v1 + v2
}
sum(10,20)
swift
// 闭包
var fn = {(_ v1: Int, _ v2: Int) -> Int in
v1 + v2
}
fn(10,20)
swift
// 闭包
var fnValue = {(_ v1: Int, _ v2: Int) -> Int in
v1 + v2
}(10,20)
swift
// 实际应用
private lazy var zipRcodeImage: UIImageView = {
let image = UIImageView()
return image
}()
// 无参数省略了 () in
14.2 闭包简写
swift
// 声明函数, 入参包含一个函数, 没有返回值 !
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
print(fn (v1, v2))
}
swift
// 1 基础写法
let fn1 = exec(v1: 10 , v2:20 , fn:{ (v1: Int, v2: Int) -> Int in
return v1 + v2
})
print(fn1) // ()
// 注意闭包的返回值 和函数的返回值不是一回事
swift
// 2 去掉闭包类型, 包含入参, 返回值类型;
// 闭包类型靠exec声明的类型推断 fn: (Int, Int) -> Int)
let fn1 = exec (v1: 10, v2: 20, fn: {
v1, v2 in return v1 + v2
// v1, v2 in v1 + v2
}
swift
// 3 再次简化 去掉参数及返回值
// 闭包类型靠exec声明的类型推断 fn: (Int, Int) -> Int)
let fn1 = exec (v1: 10, v2: 20, fn: { $0 +$1 }
let fn1 = exec (v1: 10, v2: 20, fn: { + }
14.3 尾随闭包
-
触发场景: 闭包表达式作为函数最后一个实参 -
1 尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式
swift
// 闭包表达式 非唯一参数
func exec(v1:Int,v2:Int,fn:(Int,Int)-> Int){
print(fn (v1, v2))
}
// 正常写法
exec(v1: 10, v2: 10, fn:{ v1, v2 in
v1 + v2
})
exec(v1: 10, v2: 10) { v1, v2 in
v1 + v2
} // 编译器会为你自动转为 尾随闭包
- 2 如果闭包表达式是函数的唯一实参,而且使用了尾随闭包的语法,那就不需要在函数名后边写圆括号
swift
// 闭包表达式 唯一参数
func exec (fn: (Int, Int) -> Int) {
print(fn (1, 2))
}
exec(fn: { $0 + $1 }) // 正常写法
exec(){ $0 + $1}
exec{ $0 + $1 }
swift
// 数组排序方法(系统)
func sort (by areInIncreasingOrder: (Element, Element) ->Bool
swift
func cmp(i1: Int, i2: Int) -> Bool {
// 大的排前面
return i1 > i2
}
var nums = [11, 2, 18, 6, 5, 68, 45]
nums.sort (by: cmp) // num.sort { $0>$1 }
print(nums) // [68, 45, 18, 11, 6, 5, 2]
15 闭包
定义: 一个函数和它所捕获的变量\常量环境组合起来,称为闭包
- 一般定义在函数内部的函数
- 一般他捕获的是外层函数的局部变量/常量
swift
typealias Fn = (Int) -> Int
func getFn() -> Fn {
var num = 0
func plus (_ i: Int) -> Int {
num += i
return num
}
return plus
}
let fn = getFn()
print(fn(1)) // 1
print(fn(2)) // 3
① getFn() 被调用:
- 创建局部变量
num = 0(在栈上) - 定义嵌套函数
plus - 返回
plus,plus捕获了num,num从栈转移到堆上
② 第一次调用 fn(1):
- 执行
num += 1(num从 0 → 1) - 返回 1
③ 第二次调用 fn(2):
- 同一个闭包,同一个被捕获的
num - 执行
num += 2(num从 1 → 3) - 返回 3