我是靠谱客的博主 明理水壶,最近开发中收集的这篇文章主要介绍【iOS开发--Swift语法】闭包学习记录,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

写在前面:在一开始JS基础学习的过程中,闭包的问题也曾困扰过我,其实无论是JS、OC、还是Swift,闭包的本质都是一样的。借着最近开始学习Swift,又重新将这部分复盘整理了一下。目前对于闭包相关的理解可以说是很透彻了,发现新问题再来补充。

专业的解释:

闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

形式:

Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数(Lambdas)相似。

故名思义,闭合地包起来可以完成一件事儿就是个闭包。闭包这玩意儿,只是给它取了个名字而已,全局函数其实也是个闭包。还有闭包就是自包含的函数代码块,可以在代码中被传递和使用。比如,嵌套函数,函数作为参数的情况。

全局函数

嵌套函数

闭包表达式(轻量级语法)

有名字

有名字

匿名

不会捕获任何值

捕获其外部函数所有的参数和定义的常量和变量

捕获上下文中变量或常量的值

作用:

用来解决什么问题呢?闭包解决了函数内变量暴露给函数外访问的问题。可以缓存上级作用域,那么就使得函数外部打破了“函数作用域”的束缚。

值捕获,闭包可以在上下文中捕获常量或变量的引用。即使常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。????这种情况就是值捕获

// 一般情况
// 闭包情况
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// 返回的值为7
incrementByTen()
// 返回的值为40
incrementBySeven()
// 返回的值为17

接下来,我们来对????????进行值捕获的解释????

func incrementer() -> Int {
runningTotal += amount
return runningTotal
}

「????incrementer() 函数并没有任何参数,但是在函数体内访问了 runningTotalamount 变量。这是因为它从外围函数捕获了 runningTotalamount 变量的引用。捕获引用保证了 runningTotalamount 变量在调用完 makeIncrementer 后不会消失,并且在下一次执行 incrementer 函数时,runningTotal 依旧存在。」

形式补充:

函数和闭包都是引用类型,将函数或闭包赋值给一个常量还是变量,实际上是将函数或闭包的引用设置为常量或变量的值,而并非闭包内容本身。意味着如果将闭包赋值给了两个不同的常量或变量,两个值都会指向同一个闭包。继续????例子????

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 返回的值为50

另外关于⚠️闭包引起的循环强引用问题(遇到了再说吧)

语法:

函数和返回值类型都写在大括号内

闭包的函数体部分由关键字 in 引入

{ (parameters) -> type in
    statements
}
func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
{ (s1: String, s2: String) -> Bool in
    return s1 > s2
}

语法优化:

1.省略参数和返回值类型,可根据上下文推断出

{ s1, s2 in return s1 > s2 }

2.行表达式闭包可以通过省略 return 关键字

{ s1, s2 in s1 > s2 }

3.参数名称缩写,$0 和 $1 表示闭包中第一个和第二个参数

{ $0 > $1 }

4.运算符方法【❓这个暂时先保留,知识结构补充ing】

与 sorted(by:) 方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断找到系统自带的那个字符串函数的实现:reversedNames = names.sorted(by: >)

5.尾随闭包:

将闭包表达式写在函数圆括号之后,作为函数的最后一个参数调用。用于闭包长度非常长的情况

reversedNames = names.sorted() { $0 > $1 }

若闭包表达式是函数的唯一参数,可以把 () 省略掉

reversedNames = names.sorted { $0 > $1 }

应用场景:

1.逃逸闭包:当一个闭包作为一个函数的参数,且闭包在函数返回之后才被执行。定义函数时,在参数名之前标注 @escaping指明这个闭包允许“逃逸”出这个函数。

????不想复制粘贴,具体例子移步官方文档 逃逸闭包 - SwiftGG

相信看完文档中的????对这个概念已经有了大概的理解,我来浅浅总结一下。很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回但不被调用,直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。

补充:逃逸闭包需要显示引用self

项目中的????:实现 确认是否安装外部鱼眼镜头的 Alert弹窗

//  这里isUpdateAvailable是VersionUtils的一个属性
func isUpdateAvailable(callback: @escaping (Bool) -> Void) {
callback(true)
return
}
isUpdateAvailable(callback: { isNew in
if isNew {
let alertVC = UpdateVersionAlertVC.shared
alertVC.modalPresentationStyle = .overCurrentContext
alertVC.modalTransitionStyle = .crossDissolve
self.present(UpdateVersionAlertVC.shared, animated: true)
}
}
//这里 把completed赋值给了实例 alertVC的completed属性,在alertVC的一个方法中对alertVC的completed进行传参调用,此时就需要标注@escaping(闭包需要在函数返回之后被调用)
extension FishShotAlertVC {
    @objc static func showFishShotAlertViewController(currentVC vc: UIViewController, completed: @escaping (_ isUseFishShot: Bool) -> Void) {
        let alertVC = FishShotAlertVC()
        alertVC.completed = completed
        alertVC.currentVc = vc
        vc.present(alertVC, animated: false, completion: {})
    }
}

补充:

当闭包作为函数的参数,该闭包也有参数时

1.声明函数时,不考虑闭包的具体内容,{ }里面是函数体,函数体内有对闭包进行传参调用。

2.函数调用时,作为尾随闭包,{ }里面是尾随闭包

写在最后:

学习闭包经历了三个阶段,文档看懂,写的时候语法忘了,

总而言之就是,以为懂了实际没懂,遇到实际场景返回来继续复盘,和别人讨论,直到可以回答别人提出的任何相关问题,不能解释就继续去学习。这个概念我应该算是彻彻底底懂了吧。

最后

以上就是明理水壶为你收集整理的【iOS开发--Swift语法】闭包学习记录的全部内容,希望文章能够帮你解决【iOS开发--Swift语法】闭包学习记录所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部