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)
}

 

posted @ 2017-02-17 21:47  小小聪明屋  阅读(175)  评论(0编辑  收藏  举报