zoukankan      html  css  js  c++  java
  • Swift函数和闭包

    简介:本文主要讲:函数的定义,外部参数的用处,无返回类型的三种函数定义方式

    闭包的定义,闭包的概念和用法,尾随闭包的写法,解除循环引用的方法

    一、函数:

    代码实现

    • 函数的定义
      • 格式 func 函数名(行参列表) -> 返回值 {代码实现}
      • 调用 let result = 函数名(值1, 参数2: 值2...)
    func sum(a: Int, b: Int) -> Int {
        return a + b
    }
    
    let result = sum(10, b: 20)
    
    • 没有返回值的函数,一共有三种写法
      • 省略
      • ()
      • Void
    func demo(str: String) -> Void {
        print(str)
    }
    func demo1(str: String) -> () {
        print(str)
    }
    func demo2(str: String) {
        print(str)
    }
    
    demo("hello")
    demo1("hello world")
    demo2("olleh")
    
    • 外部参数
      • 在形参名前再增加一个外部参数名,能够方便调用人员更好地理解函数的语义
      • 格式:func 函数名(外部参数名 形式参数名: 形式参数类型) -> 返回值类型 { // 代码实现 }
      • Swift 2.0 中,默认第一个参数名省略
    func sum1(num1 a: Int, num2 b: Int) -> Int {
        return a + b
    }
    
    sum1(num1: 10, num2: 20)

    二、闭包:

    与 OC 中的 Block 类似,闭包主要用于异步操作执行完成后的代码回调,网络访问结果以参数的形式传递给调用方

    闭包的定义

    • 定义一个函数
    //: 定义一个 sum 函数
    func sum(num1 num1: Int, num2: Int) -> Int {
        return num1 + num2
    }
    sum(num1: 10, num2: 30)
    
    //: 在 Swift 中函数本身就可以当作参数被定义和传递
    let mySum = sum
    let result = mySum(num1: 20, num2: 30)
    
    • 定义一个闭包
      • 闭包 = { (行参) -> 返回值 in // 代码实现 }
      • in 用于区分函数定义和代码实现
    //: 闭包 = { (行参) -> 返回值 in // 代码实现 }
    let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in
        return x + y
    }
    sumFunc(num1: 10, num2: 20)
    
    • 最简单的闭包,如果没有参数/返回值,则 参数/返回值/in 统统都可以省略
      • { 代码实现 }
    let demoFunc = {
        print("hello")
    }
    
    

    基本使用

    GCD 异步

    • 模拟在后台线程加载数据
    func loadData() {
        dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
            print("耗时操作 (NSThread .currentThread())")
        })
    }
    
    • 尾随闭包,如果闭包是最后一个参数,可以用以下写法
    • 注意上下两段代码,} 的位置
    func loadData() {
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            print("耗时操作 (NSThread .currentThread())")
        }
    }
    
    • 闭包的简写,如果闭包中没有参数和返回值,可以省略
    func loadData() {
        dispatch_async(dispatch_get_global_queue(0, 0)) {
            print("耗时操作 (NSThread .currentThread())")
        }
    }
    

    自定义闭包参数,实现主线程回调

    • 添加没有参数,没有返回值的闭包
    override func viewDidLoad() {
        super.viewDidLoad()
    
        loadData {
            print("完成回调")
        }
    }
    
    // MARK: - 自定义闭包参数
    func loadData(finished: ()->()) {
    
        dispatch_async(dispatch_get_global_queue(0, 0)) {
            print("耗时操作 (NSThread.currentThread())")
    
            dispatch_sync(dispatch_get_main_queue()) {
                print("主线程回调 (NSThread.currentThread())")
    
                // 执行回调
                finished()
            }
        }
    }
    
    • 添加回调参数
    override func viewDidLoad() {
        super.viewDidLoad()
    
        loadData4 { (html) -> () in
            print(html)
        }
    }
    
    /// 加载数据
    /// 完成回调 - 传入回调闭包,接收异步执行的结果
    func loadData4(finished: (html: String) -> ()) {
    
        dispatch_async(dispatch_get_global_queue(0, 0)) {
            print("加载数据 (NSThread.currentThread())")
    
            dispatch_sync(dispatch_get_main_queue()) {
                print("完成回调 (NSThread.currentThread())")
    
                finished(html: "<h1>hello world</h1>")
            }
        }
    }


    循环引用

    • 建立 NetworkTools 对象
    class NetworkTools: NSObject {
    
        /// 加载数据
        ///
        /// - parameter finished: 完成回调
        func loadData(finished: () -> ()) {
            print("开始加载数据...")
    
            // ...
            finished()
        }
    
        deinit {
            print("网络工具 88")
        }
    }
    
    • 实例化 NetworkTools 并且加载数据
    class ViewController: UIViewController {
    
        var tools: NetworkTools?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tools = NetworkTools()
            tools?.loadData() {
                print("come here (self.view)")
            }
        }
    
        /// 与 OC 中的 dealloc 类似,注意此函数没有()
        deinit {
            print("控制器 88")
        }
    }
    

    运行不会形成循环引用,因为 loadData 执行完毕后,就会释放对 self 的引用

    • 修改 NetworkTools,定义回调闭包属性
    /// 完成回调属性
    var finishedCallBack: (()->())?
    
    /// 加载数据
    ///
    /// - parameter finished: 完成回调
    func loadData(finished: () -> ()) {
    
        self.finishedCallBack = finished
    
        print("开始加载数据...")
    
        // ...
        working()
    }
    
    func working() {
        finishedCallBack?()
    }
    
    deinit {
        print("网络工具 88")
    }
    

    运行测试,会出现循环引用

    解除循环引用

    • 与 OC 类似的方法
    /// 类似于 OC 的解除引用
    func demo() {
        weak var weakSelf = self
        tools?.loadData() {
            print("(weakSelf?.view)")
        }
    }
    
    • Swift 推荐的方法
    loadData { [weak self] in
        print("(self?.view)")
    }
    
    • 还可以
    loadData { [unowned self] in
        print("(self.view)")
    }
    

    闭包(Block) 的循环引用小结

    • Swift

      • [weak self]
        • self是可选项,如果self已经被释放,则为nil
      • [unowned self]
        • self不是可选项,如果self已经被释放,则出现野指针访问
    • Objc

      • __weak typeof(self) weakSelf;
        • 如果self已经被释放,则为nil
      • __unsafe_unretained typeof(self) weakSelf;
        • 如果self已经被释放,则出现野指针访问
  • 相关阅读:
    013.ES6 -对象字面量增强型写法
    012. ES6
    011. ES6 语法
    10. 9. Vue 计算属性的setter和getter 以及 计算属性的缓存讲解
    4. Spring MVC 数据响应方式
    3. SpringMVC 组件解析
    9. Vue 计算属性
    【洛谷 2984】给巧克力
    【洛谷 1821】捉迷藏 Hide and Seek
    【洛谷 1821】银牛派对Silver Cow Party
  • 原文地址:https://www.cnblogs.com/evening015/p/5349089.html
Copyright © 2011-2022 走看看