Swift5.1 闭包

Swift5.1 闭包笔记

闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数(Lambdas)比较相似。
在这里插入图片描述

import UIKit

var str = "Hello, playground"
print(str)
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
// sorted(by:) 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回 true,反之返回 false。
func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}

var reversedNames = names.sorted(by: backward)
print(reversedNames)

/// 闭包表达式语法

///{ (parameters) -> return type in
///    statements
///}

///(String , String) -> Bool

/// 闭包表达式基本语法
reversedNames = names.sorted(by: { (s1: String , s2: String) -> Bool in return s1 > s2 })
print("内联闭包表达式\(reversedNames)")

/// 根据上下文推断类型
///实际上,通过内联闭包表达式构造的闭包作为参数传递给函数或方法时,总是能够推断出闭包的参数和返回值类型。这意味着闭包作为函数或者方法的参数时,你几乎不需要利用完整格式构造内联闭包
reversedNames = names.sorted(by: { s1 ,s2 in return s1 > s2  })
print("根据上下文推断类型\(reversedNames)")

/// 单表达式闭包和隐式返回 无return
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 })

/// 参数名称缩写 自动为内联闭包提供了参数名称缩写功能,你可以直接通过 $0,$1,$2
reversedNames = names.sorted(by: { $0 > $1 })
print("参数名缩写\(reversedNames)")

/// 运算符方法
/// 其作为一个函数接受两个 String 类型的参数并返回 Bool 类型的值。而这正好与 sorted(by:) 方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断找到系统自带的那个字符串函数的实现:
reversedNames = names.sorted(by: >)


/// 尾随闭包 (block)
//  尾随闭包是一个书写在函数圆括号之后的闭包表达式,函数支持将其作为最后一个参数调用。

func someFunctionThatTakesAClosure(closure: () -> Void) {
    //函数内容
}

// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure(closure: {
    //闭包主体部分
})

//  以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
    //闭包主体部分
}

/// 使用尾随闭包的形式改写在 sorted(by:) 方法圆括号的外面:
reversedNames = names.sorted(){ $0 > $1 }
//如果闭包表达式是函数或方法的唯一参数,则当你使用尾随闭包时,你甚至可以把 () 省略掉:
reversedNames = names.sorted {$0 > $1}

/// 数组中使用尾随闭包
let digitNnames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]

let numbers = [16,58,510]

let strings = numbers.map { (number) -> String in
    var number = number
    var output = ""
    repeat {
        output = digitNnames[number % 10]! + output
        number /= 10
    } while number > 0
    return output
}
print("尾随闭包\(strings)")


/// 值捕获
//嵌套函数
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal  = 0
//    print("makeIncrementer 外\(runningTotal)")
    func incrementer() -> Int {
        //捕获引用保证了 runningTotal 和 amount 变量在调用完 makeIncrementer 后不会消失,并且保证了在下一次执行 incrementer 函数时,runningTotal 依旧存在。
//        print("incrementer 内 \(runningTotal)")
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

//为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,Swift 可能会改为捕获并保存一份对值的拷贝。
let incrementByTen = makeIncrementer(forIncrement: 10)

//调用方法多少只会
print(incrementByTen())
print(incrementByTen())
print(incrementByTen())
print(incrementByTen())
print(incrementByTen())

let incrementBySeven = makeIncrementer(forIncrement: 7)

print(incrementBySeven())
print(incrementByTen())
print(incrementBySeven())

/// 逃逸闭包 (@escaping 最后执行)
//当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,用来指明这个闭包是允许“逃逸”出这个函数的

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    print("逃逸闭包")
    completionHandlers.append(completionHandler)
}

func someFunctionWihtNoescapingClosure(closure: () -> Void) {
    print("闭包")
    closure()
}

/// 将一个闭包标记为 @escaping 意味着你必须在闭包中显式地引用 self
class SomeClass {
    var x = 10
    func doSomething() {
        print("进入 doSomething")
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWihtNoescapingClosure { x = 200 }
    }
}
let instance = SomeClass()
instance.doSomething()
print("隐式\(instance.x)")

completionHandlers.first?()
print("显示\(instance.x)")

/// 自动闭包 (@autoclosure 只有调用的时候才执行)

//自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够省略闭包的花括号,用一个普通的表达式来代替显式的闭包。

//自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)

let customerProvider = { customersInLine.remove(at: 0) } //返回值 () -> String,一个没有参数且返回值为 String 的函数
print(customersInLine.count)

print("Now serving \(customerProvider())!")
print(customersInLine.count)

//将闭包作为参数传递给函数时,你能获得同样的延时求值行为
func serve(customer customerProvider: @autoclosure  () -> String) {
    print("Now serving \(customerProvider())!")
}

serve(customer: customersInLine.remove(at: 0))

/// 如果你想让一个自动闭包可以“逃逸”,则应该同时使用 @autoclosure 和 @escaping 属性。
// customersInLine i= ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
    customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))

print("Collected \(customerProviders.count) closures.")
// 打印“Collected 2 closures.”
for customerProvider in customerProviders {
    print("Now serving \(customerProvider())!")
}
// 打印“Now serving Barry!”
// 打印“Now serving Daniella!”
//在上面的代码中,collectCustomerProviders(_:) 函数并没有调用传入的 customerProvider 闭包,而是将闭包追加到了 customerProviders 数组中。这个数组定义在函数作用域范围外,这意味着数组内的闭包能够在函数返回之后被调用。因此,customerProvider 参数必须允许“逃逸”出函数作用域。

参考:
闭包-SwiftGG
官方文档 Closures

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值