Swift4 闭包及其应用 【Update】

闭包 closure

闭包在Swift中应用广泛,在许多系统库方法中都能看到。

  • 无名
  • 本质是函数
  • 使用时注意循环引用
闭包基础
//闭包是无名的,因为他们能够从上下文中捕获变量、常量,从而应用在自身的作用区域。

//声明
var myClosure: () -> String
//注意 () -> String 实际上是一个无名函数,作为闭包变量的类型。

//无返回值的闭包
myClosure:() -> Void = {
    print("Hello world")
}

//新版Xcode10中出现错误提示
//疑似以下两个原因造成:
//1. 加强了 Swift 类型检测, () -> String   ----> () -> Void  
//2. 闭包赋值时,无需在多余强调类型 
//故纠正如下:
myClosure = {
  print("Hello world")
  //这里根据 返回值类型予以纠正
 //() -> String
 //return "anyThing"
}

//执行闭包
myClosure() // Hello world


//尝试一个带参的闭包
var mySecondClosure: (Int , Int ) -> Int = {
    (a: Int , b: Int) -> Int in 
    return a * b
}

//第一次简化 类型自动推导 可以根据参数推断
mySecondClosure = {
    (a, b) in 
    return a * b
}

//第二次简化 如果函数体只包含一句 return 代码,可省略 return
mySecondClosure = {
    (a, b) in 
    a * b
}

/*
第三次简化 
被捕获的参数列表中,含有a、b,下标从0开始,可通过"$"获取。

编译器亦可通过,捕获列表自行推断出参数。
故可省略参数列表 (a, b)和 关键字 in 
*/
mySecondClosure = {
    $0 * $1
}

闭包作为函数参数
/*
operation: 是一个闭包类型的参数
该闭包有两个参数(Int, Int) ,并有一个Int型返回值

要整体看待,不要蒙圈。
*/
func myOpreation(_ a: Int , _ b: Int, operation: (Int , Int) -> Int) -> Int {
    let res = operation(a, b)
    return res
}

//实现一个闭包
let multipyClosure:(Int, Int) -> Int = {
    $0 * $1
}

//等同于
let multipyClosure = {
    (a: Int, b: Int) in 
    a * b
}

//下面,我们将闭包作为参数传递
myOperation(4, 2, operation:multipyClosure)

//展开 inline
myOperation(4, 2, operation: {
    (a: Int, b: Int) -> Int in 
    return a * b
})


/*
事实上,我们并没有必要在本地定义一个闭包常量或变量,再作为参数传递。
可以简单的在调用的地方进行声明并简化
*/

myOperation(4, 2, operation:{
    $0 * $1
})

//进一步简化,* 操作符是一个有两个参数并返回一个结果的函数。可做如下简化:
myOperation(4, 2, operation: *)

/*
如果闭包是作为函数的最后一个参数,可以将闭包后置到函数体外部。 
*/
myOperation(4, 2) {
    $0 * $1
}

捕获

闭包可以从上下文环境中捕获常量、变量,并在自己的作用域内使用。

//eg.: 1
var counter = 0
let incrementCounter = {
    counter += 1    
}

/*
由于闭包定义和变量counter在同一作用域中,
故闭包可以捕获并访问变量counter。
对变量counter做的任何改变,对闭包来说都是透明可见的。
*/

incrementCounter() //1
incrementCounter() //2

//eg.: 2
func countingClosure() -> () -> Int {
    var counter = 0
    let incrementCounter: () -> Int = {
    counter += 1
    return counter
    }
    return incrementCounter
}

/*
该例子中,闭包捕获了封闭空间(函数实体内)的内部变量counter。
*/


let counter1 = countingClosure()
let counter2 = countingClosure()

counter1() // 1
counter2() // 1
counter1() // 2
counter1() // 3
counter2() // 2

应用闭包在集合中

排序
/*
数组提供了一个排序函数,sorted().使用的是默认规则,当然我们也可以定制排序规则。
*/

let names = ["ZZZZZZ", "BB", "A", "CCCC", "EEEEE"]
names.sorted()
// ["A", "BB", "CCCC", "EEEEE", "ZZZZZZ"]

//更改排序规则 其实就是利用了函数重载,具体可看函数定义
//sorted(by: <#T##(String, String) throws -> Bool#>)

names.sorted {
    $0.count > $1.count
}
// ["ZZZZZZ", "EEEEE", "CCCC", "BB", "A"]

遍历
集合提供了很多遍历的函数用来对元素进行访问及操作,并大量应用了闭包。
重点需要了解的函数有: 
forEach、filter、map、reduce
  • forEach
/*
循环遍历集合中的元素,相当于for-in 快速遍历    
*/

let values = [5, 3, 2, 3,1]
values.forEach {
    print("element is \($0)")
}
  • filter
/*
函数原型:
 func filter(_ isIncluded: (Element) -> Bool) -> [Element]
 
 按照规则过滤原数组
*/

var values = [1.5, 10, 4.88, 3.2, 8]

let res = values.filter {
    return $0 > 4
}

//res是移除掉小于或等于4的元素的新数组
  • map
/*
函数原型:
students.map(<#T##transform: (String) throws -> T##(String) throws -> T#>)

数组映射
*/

let input = ["0", "12", "name", "hi", "3"]

let number = input.map {
    Int($0) //将元素转换为Int型
}
//注意类型转换可能失败,所以返回的是可选型
//[Optional(0), Optional(12), nil, nil, Optional(3)]

/*
另外一个高度近似的函数
flatMap
隐含了两种操作
1.解包
2.展开并合并
*/

let flatNumber = input.flatMap() {
    Int($0)
}
//[0, 12, 3]


  • reduce
/*
函数原型
reduce(<#T##initialResult: Result##Result#>, <#T##nextPartialResult: (Result, String) throws -> Result##(Result, String) throws -> Result#>)

*/

//数组
let flatNumber = [0, 12, 3]

let sum = flatNumber.reduce(0) {
    return $0 + $1
}
//15

//字典
let stock = [1.5: 5, 10: 2, 4.99: 20, 2.30: 5, 8.19: 30]
let stockSum = stock.reduce(0) {
  return $0 + $1.key * Double($1.value)
}
//384.5

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

推荐阅读更多精彩内容

  • 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代...
    穷人家的孩纸阅读 1,697评论 1 5
  • 以下翻译自Apple官方文档,结合自己的理解记录下来。翻译基于 swift 3.0.1 原文地址 Closure...
    艺术农阅读 1,511评论 0 3
  • 闭包 闭包是自包含的功能块,可以在代码中传递和使用。Swift中的闭包与C和Objective-C中的块以及其他编...
    Fuuqiu阅读 359评论 0 0
  • C++ 继承 派生类在继承时默认的访问修饰符为 private,一般都会使用 public,这样才能继承基类 pu...
    谢小帅阅读 347评论 0 0
  • 132566889
    Sunshine_d1b0阅读 243评论 0 0