Swift中的闭包

1.可以理解成OC 中使用的block,但是本质不一样.
2.Swift中使用的是 闭包.
3.闭包是一个代码块.
4.在我们需要的时候执行.
5.闭包可以作为 参数 或者 返回值.
6.闭包内 使用self 注意 循环引用.
7.将“函数、函数指针、闭包”三者对比起来理解,能加深对闭包的理解:
函数: 具有特定功能的代码块;
函数指针: 指向函数的指针;
闭包:除具备“函数和函数指针”的所有功能外, 还包括声明它的上下文(如作用域内的自由变量等).

接下来的闭包定义都是参照函数的定义方式类比下来的, 便于记忆理解.

1.无参数 无返回值的闭包

    // 无参数 无返回值的函数
    func demoA1(){
        
        func sum(){
            print("无参数 无返回值的函数")
        }
        // 函数的调用 : 函数名()
        sum()
    }
    
    // 注意: 闭包就是 代码块 也就是{}, 用一个名称来记录它
    let closure1 = {}
    // 通过自动推导可以得出, 上面的常量closure 的类型为 ()->(), 因次得出:
    // 闭包的类型 是 ()->(), 前一个括号里面代表所需要的参数, 后一个括弧里面代表返回值
    // 也就是正常的闭包格式: let closure1: ()->() = {}
    // 在无参数无返回值的闭包里面 ()-()可以省略不写
    // 重点: 因为闭包是代码块, 因此所有的东西都要写在块里面, 这也是与函数的写法的区别!!!
    
    // 类比上面的函数来定义 -> 无参数无返回值的闭包
    func demoA2(){
        
        let closure = {()->() in
            print("无参数无返回值的闭包")
        }
        // 闭包的调用
        closure()
    }

2.有参数 无返回值的闭包

    // 有参数 无返回值的函数
    func demoB1(){
        
        func sum(a: Int){
            print(a)
        }
        // 函数的调用 : 函数名()
        sum(a: 8)
    }
    
    // 注意: 因为闭包是代码块, 因此所有的东西都要写在块里面, 这也是与函数的写法的区别!!!
    // 规则: 当将闭包的参数或返回值写在块里面的同时, 需要在返回值后面添加 in 来把闭包的参数或者返回值 与 闭包内部的逻辑隔开
    // 格式: let closure = {()->() in 闭包内部的代码逻辑}
    // 类比上面的函数来定义 -> 有参数无返回值的闭包
    func demoB2(){
        
        let closure = {(a: Int)->() in
            print(a)
        }
        // 闭包的调用
        closure(3)
    }
    
    // 同时, 仿照有参数 无返回值的函数, 有参数无返回值的闭包还有两种写法
    func demoB3(){
        
        let closure = {(a: Int)->Void in
            print(a)
        }
        // 闭包的调用
        closure(3)
    }
    // 或者 -- 这是最正常的,也是最多的一种写法
    func demoB4(){
        
        let closure = {(a: Int) in
            print(a)
        }
        // 闭包的调用
        closure(3)
    }

3.有参数 有返回值的闭包

    // 有参数 有返回值的函数
    func demoC1(){
        
        func sum(a: Int, b: Int) -> Int{
            return a + b
        }
        // 函数的调用 : 函数名()
        let result = sum(a: 3, b: 8)
        print(result)
    }
    
    // 类比上面的函数来定义 -> 有参数有返回值的闭包
    func demoC2(){
        
        let closure = {(a: Int, b: Int) -> Int in
            return a + b
        }
        // 闭包的调用
        let result = closure(9, 9)
        print(result)
    }

4. 总结: 闭包的格式
闭包定义的格式总结

5.闭包的实际演练(模拟加载数据)

5.1 传递的数据做闭包的参数还是返回值?
    /*
     1. 情景分析: 模拟加载数据, 当数据加载完成时, 传递数据显示到界面, 而不是一直等待, 体现闭包: 使用的时候才加载的特性, 不需要一直等待.
     2. 思考? 传递数据的时候, 数据是作为闭包的参数, 还是返回值???
    
     分析: 当传递的数据作为返回值,
     2.1 声明
     let closure = { (a: Int) -> Int in
        return a
     }
     
     2.2 调用
     let result = closure(5)
     
     2.3 结果分析
     这就相当于 在我传入5的时候得到5, 这不是自己在和自己玩嘛, 我已经是几了, 还调用一下干嘛...再说是外界需要这个数据, 我只是在加载而已, 所以传递的数据做为返回值根本不能满足对外界传递数据的需要.
     
     2.4 结论: 所以传递的数据要作为闭包的参数!
     */
5.2 闭包作为函数参数的写法和使用步骤
    /* 写法:
     模拟 OC 函数的参数的写法, 实现 Swift 中函数参数的书写
     :(int) a   OC中正常的数据类型做为参数的写法;
     a: Int     Swift中正常的数据类型作为参数的写法;
     a: ()->()  Swift中闭包作为参数的写法
     注意: 当闭包(()->())作为参数的时候,  两个小括弧里面只写上数据类型即可.
     */
    
    /* 使用步骤: 3步
     1. 在 需要得到数据 的地方 定义和实例化闭包.
     2. 在 能够得到数据 的地方, 得到数据的时候, 调用闭包.
     3. 在闭包的 块的作用域 中, 得到闭包回调的结果.
     */
5.3 模拟代码
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // 1. 在想要得到数据的地方, 定义和实例化闭包
        let closure = {(result: String) -> () in
            // 3. 得到闭包回调的结果
            print(result) // 运行之后, 延迟2面, 打印:不想睡
        }
        
        loadData(callBack: closure)
    }
    
    // 模拟加载数据
    func loadData(callBack: @escaping (String) -> ()){
        // 子线程异步加载数据
        DispatchQueue.global().async {
            // 模拟消耗时间
            Thread.sleep(forTimeInterval: 2.0)
            // 模拟请求回来的数据, 要传递给viewDidLoad中使用
            let data = "不想睡"
            // 回到主线程, 刷新页面
            DispatchQueue.main.async {
                // 2. 在得到数据的时候,执行闭包
                callBack(data)
            }
        }
    }
5.4 @escaping关键字
    /*
     1. 在上一段模拟代码中, 我们发现一个修饰闭包的关键字, @escaping.
     2. 不必过度关注, 一般情况下Xcode会自动提示添加该关键字.
     3. @escaping的使用时机:
        3.1 闭包在其他线程执行 (上一段代码就是在其他线程执行了闭包)
        3.2 对传入的闭包进行了赋值操作(包括定义一个新的变量/常量来记录该闭包的时候, 见下面代码)
     */
    func loadData(callBack:@escaping (String) -> ()){
        
        let clo = callBack
        clo("@escaping关键字")
    }
5.5 @escaping关键字 更新一波

\color{red}{ 在swift5.0之后, 只有闭包在其他线程执行时才需要添加该关键字, 且Xcode会报错, 但不再有自动提示添加该关键字的功能 }

6.尾随闭包

就是系统的简写方式,了解即可. 以下两种情况为尾随闭包.

条件1: 定义的函数有且只有一个参数, 并且参数是闭包,函数调用时,( )可以省略.

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // 1.0 正常写法
        let closure = { (result: String) in
            
        }
        loadData(callback: closure)
        // 1.1 可以演变成
        loadData(callback:  { (result: String) in
            
        })
        
        // 2.0 尾随闭包写法: 直接写loadData方法, 按回车,自动联想, 原理是->()和里面的参数名称可以省略, 参数类型也可以省略
        loadData { (result) in
            
        }
    }
    
    func loadData(callback: (String)->()){
        
    }

条件2: 定义的函数有多个参数, 但是最后一个参数为闭包 , 函数的( )提前关闭.

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // 1.0 正常写法
        let closure = { (result: String) in
            
        }
        loadData(a: 3, b: "8", callback: closure)
        // 1.1 可以演变成
        loadData(a: 3, b: "8", callback: { (result: String) in
            
        })
        
        // 2.0 尾随闭包写法: 直接写loadData方法, 按回车,自动联想, 原理是->()里面的参数名称可以省略, ()提前闭合, 只留下闭包了,闭包的参数类型也可以省略
        loadData(a: 3, b: "8") { (result) in
            
        }
    }
    
    func loadData(a: Int, b: String, callback: (String)->()){
        
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359

推荐阅读更多精彩内容

  • 一、简介 闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。Swift 中的闭包...
    凡几多阅读 2,321评论 2 5
  • 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代...
    CodingIran阅读 323评论 0 0
  •   1、闭包的概念   一门计算机语言如果要支持闭包,必须要有两个前提:支持函数类型,也就是说可以将函数作为参数进...
    落叶刺客阅读 682评论 0 0
  • swift中的闭包 闭包是自包含的函数代码块,可以在代码中被传递和使用。swift中的闭包与C和Objective...
    陈藩阅读 214评论 0 0
  • 饶德美阅读 121评论 0 0