Swift学习之闭包

一、闭包表达式

在Swift中,可以通过func定义一个函数。也可以通过闭包表达式定义一个函数

func test(v1:Int,v2:Int) ->Int {
    return v1 + v2;
}
-----------------------------------------------------------------------
let fn =   {
            (v1:Int,v2:Int) ->Int in
            return v1 + v2;
           }
print(fn(10,20));
  • 闭包表达式语法基本形式
  { (parameters) -> (return type) in
    statements
  }

闭包的函数整体部分由关键字 in 导入,这个关键字表示闭包的形式参数类型和返回类型定义已经完成,并且闭包的函数体即将开始。

  • 定义一个闭包表达式
let fn =   {
            (v1:Int,v2:Int) ->Int in
            return v1 + v2;
           }
print(fn(10,20));
import UIKit
class Student{
    func test(){
        {
            (v1:Int,v2:Int) ->Int in
            
            print("闭包表达式")
            return v1 + v2;
        }(10,20)
    }
}
let s = Student()
s.test()
  • 闭包表达式的类型
    闭包表达式本质是函数,其类型和函数的类型一样。可分为: () -> (),(Int) -> (),(Int) -> (Int),() -> (Int) ······等

二、闭包表达式作为参数传递

- (void)execWithFn:( NSInteger (^)(NSInteger, NSInteger))fn{
    fn(10,20);
}

oc中block可以作为函数的参数进行传递,swift中闭包当然也可以作为函数的参数进行传递

class Student{
    func exec(fn: (Int,Int) -> Int) {
       print(fn(1,2))
    }
}
let s = Student()
s.exec (fn: { (v1:Int, V2:Int) -> Int in
    print("闭包")
    return v1 + V2
})
class Student{
    func exec(a:Int,b:Int,fn: (Int,Int) -> Int,c:Int) {
       print(fn(1,2))
    }
}

let s = Student()
s.exec (a:10,b:20,fn: { (v1:Int, V2:Int) -> Int in
    print("闭包")
    return v1 + V2
},c:21)

三、尾随闭包

如果你需要将一个很长的闭包表达式作为函数最后一个实际参数传递给函数,使用尾随闭包将增强函数的可读性。尾随闭包是一个被书写在函数形式参数的括号外面(后面)的闭包表达式。

class Student{
    func exec(a:Int,b:Int,fn: (Int,Int) -> Int) {
       print(fn(1,2))
    }
}
let s = Student()

//未使用尾随闭包
s.exec (a:10,b:20,fn: { (v1:Int, V2:Int) -> Int in
    print("未使用尾随闭包")
    return v1 + V2
})

//使用了尾随闭包
s.exec (a: 10, b: 20){ (c:Int, d:Int) -> Int in
    print("使用了尾随闭包")
    return c + d
}
  • 如果闭包是函数的最后一个参数,则可以将闭包写在()后面,这种写法就是尾随闭包。

class Student{
    func exec(fn:(Int,Int) -> Int) {
       print(fn(1,2))
    }
}
let s = Student()
s.exec { (c:Int, d:Int) -> Int in
    return c + d
}
  • 如果闭包表达式是函数的唯一实参,而且使用了尾随的语法,那就可以省略函数名后的圆括号。

四、自动闭包

官方解释:自动闭包是一种自动创建的用来把作为实际参数传递给函数的表达式打包的闭包。它不接受任何实际参数,并且当它被调用时,它会返回内部打包的表达式的值。这个语法的好处在于通过写普通表达式代替显式闭包而使你省略包围函数形式参数的括号。

func test(wage:Int,fn:()->(Int)){
    if wage<5000 {
      
        print("不用交税")
    }else{
        print("\(fn())元要交税")
    }
}

var wage = 8000
test(wage: wage){
  return (wage-5000)
}

wage = 2000
test(wage: wage){
    return (wage-5000)
}

以上代码的意思是,当wage = 8000,需要交wage-5000的税,而wage =2000,不需要交税。不需要交税我们就不必去计算wage-5000。我们设计 test函数中计算税的表达式为一个闭包参数,这样就可以在需要的时候执行,提高了效率。

以上是正常的闭包定义和调用,如果我们使用了自动闭包

func test(wage:Int,fn:@autoclosure()->(Int)){
    if wage<5000 {
      
        print("不用交税")
    }else{
        print("\(fn())元要交税")
    }
}
var wage = 8000
test(wage: wage,fn: wage-5000)

wage = 2000
test(wage:wage, fn:wage-5000)

wag-5000是一个整数运算表达式,却能传递给类型为闭包的参数fn,很惊喜吧。这是@autoclosure标记后,test(wage: wage,fn: wage-5000)虽然fn表面上看传递的是wage-5000,编译器会自动把传递的表达式加上{},从而转换为闭包{wage-5000}。也就是最终的调用是test(wage: wage,fn: {wage-5000})。这就是自动闭包吧。我们这时再去看官方的解释,也许就会理解它所表达的意思。

  • @autoclosure 会自动将 20 封装成闭包 { 20 }
  • @autoclosure 只支持 () -> T 格式的参数
  • @autoclosure 并非只支持最后1个参数
  • 空合并运算符 ?? 使用了 @autoclosure 技术
  • 有@autoclosure、无@autoclosure,构成了函数重载

五、逃逸闭包

逃逸闭包、非逃逸闭包,一般都是当作参数传递。

1、非逃逸闭包

func test(_ fn:(Int,Int) -> Int){
    fn(1,2)
}

 test ({ (v1:Int, v2:Int) -> Int in
    v1 + v2
})

闭包fn的调用是在test函数作用域内,发生在 函数结束前。这就是非逃逸闭包

2、逃逸闭包

import UIKit

class Person {
var testFn:(Int,Int) ->Int

    init(fn:@escaping (Int,Int)->Int) {
        self.testFn = fn
    }
    
}

var p = Person(fn:
           {
            
            (v1:Int,v2:Int) in
            
             v1 + v2 
          
           }
)
print(p.testFn(1,2))

闭包fn的调用不是直接在函数内调用,而是在init函数外调用,闭包调用了逃离了函数的作用域,这就是逃逸闭包。需要用@escapings声明

  • 非逃逸闭包:闭包的调用发生在函数结束前,闭包调用在函数作用域内
    -逃逸闭包:闭包有可能在函数结束后调用,闭包调用逃离了函数的作用域

六、闭包

一个函数和它所捕获 的变量\常量组合起来,称之为 闭包

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容

  • 闭包引入 计算1个数的平方 函数写法 闭包写法 闭包含义 闭包是可以被传递和引用的一个独立模块 闭包能够捕获和存储...
    YungFan阅读 2,029评论 0 17
  • 闭包的介绍 闭包和OC中的block非常相似 OC中的block是匿名的函数 Swift中的闭包是一个特殊的函数 ...
    CoderLWG阅读 225评论 0 0
  • 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代...
    雨影阅读 717评论 0 2
  • 本章将会介绍 闭包表达式尾随闭包值捕获闭包是引用类型逃逸闭包自动闭包枚举语法使用Switch语句匹配枚举值关联值原...
    寒桥阅读 1,559评论 0 3
  • swift中闭包类似于oc中的Block语句块 一、一个最简单的闭包实现 🌰1 闭包就是写好的一段代码,然后在某一...
    巧克力的qiao阅读 282评论 0 2