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已经被释放,则出现野指针访问
  • 相关阅读:
    查询数据库版本
    Appscan的安装破解以及使用
    jmeter接口性能测试【CSV文件读取+接口关联+设置集合点】
    常用命令记录
    jmeter接口自动化-通过csv文件读取用例并执行测试
    js函数
    js数据类型及方法
    初识js(第一篇)
    一个人记笔记多没意思啊,拿出来分享一下咯
    博客园设置访问数量统计-小试牛刀
  • 原文地址:https://www.cnblogs.com/evening015/p/5349089.html
Copyright © 2011-2022 走看看