Swift学习笔记八:函数与闭包
函数
- 函数的定义: 函数名(形参列表) -> 返回类型
// 有返回值 与 参数 // 类型: (Int, Int) -> Int func sum(x: Int, y: Int) -> Int { return x + y } sum(x: 10, y: 11) // 无返回值 // 类型: (Int, Int) -> () funcsum4(x:Int, y:Int) { print(x + y) } sum4(x: 10, y: 11)
- 函数的外部参数
- 外部参数是在 形参 前加一个名字
- 外部参数不会影响函数内部的细节
- 外部参数会让外部调用方看起来更加的直观
- 如果没有写外部参数, 函数在调用时, 默认会显示一个与形参变量同名的外部参数
- 外部参数如果使用 _ , 在外部调用时, 会忽略形参的名字
- 在 Swift 中, 使用 _ 就是可以忽略任意不感兴趣的内容
// 类型: (Int, Int) -> Int funcsum(x:Int, y:Int) ->Int { return x + y } sum(x: 10, y: 11) // 类型: (Int, Int) -> Int func sum1(num1 x: Int, num2 y: Int) -> Int { return x + y } sum1(num1: 1, num2: 2)
- 函数的默认值
// 通过给参数设定默认值, 在调用的时候可以任意纵使参数; 如果不指定的, 就使用默认值 func sum3(x: Int = 1, y: Int = 2) -> Int { return x + y } sum3() sum3(x: 10) sum3(y: 1) sum3(x: 10, y: 20)
- 输入输出函数
- 当想要通过函数改变外部变量的值时, 在参数定义的类型的前面加 inout 关键字
- 注意: 输入输出函数不能有默认值
var x1 = 10 var x2 = 99 func demo(x: inout Int, y: inout Int) { let temp = x x = y y = temp } demo(x: &x1, y: &x2) print("*******\(x1) ******\(x2)")
闭包
- 在 OC 中 block 是匿名的函数
- 在 Swift 中函数是特殊的闭包
// 最简单的闭包 // () -> () 没有参数, 没有返回值的函数 // 如果 没有参数, 没有返回值, 可以省略, 连 in 都一起省略 let b1 = { print("hello") } b1() // 带参数的闭包 // 闭包中, 参数, 返回值, 实现代码都是写在 {} 中 // 需要使用一个关键字 in, 来分隔 定义 与 实现 // { 形参列表 -> 返回值类型 in 实现代码 } // (Int) -> () let b2 = {(x: Int) -> () in print(x) } b2(10) // (Int) -> (Int) let b3 = {(x: Int) -> (Int) in print(x) return 10 } b3(10)
- 尾随闭包
- 如果函数的最后一个参数是闭包, 函数参数可以提前结束, 最后一个参数使用 {} 包装闭包的代码, 函数的闭包参数的外部名称省略
- 通过内联闭包表达示构成的闭包作为参数传递给函数或方法时, 总是能够推断出闭包的参数和返回值的类型, 因此, 闭包的参数和返回值的类型是可以省略的, 返回箭头 -> 和围绕在参数周围的括号也可以省略
// @escaping: 逃逸闭包(函数返回之后再调用闭包) func text(completion: @escaping ([String]) -> ()) { DispatchQueue.global().async { print("耗时操作\(Thread.current)") // 模拟耗时操作 Thread.sleep(forTimeInterval: 2) let array = ["1", "2", "3", "4"] // 主线程更新 UI DispatchQueue.main.async { print("主线程更新 UI \(Thread.current)") completion(array) } } } // 函数调用的完整写法 text(completion: { (result: [String]) -> () in print("请求到的网络数据*********\(result)") }) // 函数调用的简写, 省略: 函数的闭包参数的外部名称(completion) 闭包参数的类型([String]) 箭头(->) 闭包参数的返回值类型() text() { result in print("请求到的网络数据*********\(result)") } // 函数调用的简写 text { (result) in print("请求到的网络数据*********\(result)") }
- 闭包的循环引用
// 闭包中如果出现的 self, 要特别小心 // 循环引用 单方向引用是不会产生循环引用的 // 如果只是 闭包 对 self 进行了 copy, 闭包执行写成之后, 会自动销毁, 同时释放对 self 的引用 // 同时需要 self 对闭包引用 // 解决循环引用的方法 // 方法1. OC 的方式 // weak 只能修饰 var, 不能修饰 let, 因为 weak 修饰的变量可能在运行时被修改 ---> 指向的对象一旦被释放, 会被自动设置为 nil weak var weakSelf = self loadData { print(weakSelf?.view) } // 方法2. Swift 的推荐方法 // [weak self] 表示 {} 中的所有 self 都是弱引用, 需要注意解包 loadData { [weak self] in print(self?.view) } // 方法 3. // [unowned self] 表示 {} 中的所有 self 都是 assign 的, 不会强引用, 但是, 如果对象被释放, 指针地址不会变化, 如果对象被释放, 继续调用, 就会出现野指针的问题 loadData { [unowned self] in print(self.view) }