前语

Swift 是一门现代化的编程言语,它在许多方面都充满创新和便利性。在 Swift 中,闭包 是一项强壮的特性,它为开发者供给了一种灵敏、轻量级的函数式编程办法。本文我将总结一下我深化研究后关于 Swift中 闭包 的概念,品种和写法以及一些实践的运用。

一、闭包的概念

信任大家网上一搜都查到这么一句话:

  闭包是一种自包含的功用代码块,是能够被传递和用作参数的函数。

那么这句话应该怎么了解呢?需求了解这句话,需求首先了解 Swift 中函数是一等公民(First-Class Citizen)的概念。

  所谓”榜首等公民”(first class),指的是其他数据类型相同,处于相等位置,能够赋值给其他变量,也能够作为参数,传入另一个函数,或许作为其他函数的回来值。

  而Swift 中的函数和闭包都是一等公民,因而闭包既能够被当作参数传递给函数,也能够赋值给变量,还能够作为函数的回来值。

二、闭包的品种

闭包有三种办法:大局函数、嵌套函数和闭包表达式。

1.大局函数

大局函数是一个特别的闭包。他具有姓名但不捕获任何值,界说在大局效果域内,例如以下代码:

// 大局效果域中的函数
//`person是`greet` 函数的参数,而不是捕获的值。
func greet(person: String) -> String {
    return "Hello, (person)!"
}
let greeting = greet(person: "Alice")
print(greeting) // 输出: Hello, Alice!

2.嵌套函数

嵌套函数是在其他函数内部界说的函数,也是一个特别的闭包,它具有姓名,能够捕获其包含函数的参数和常量。嵌套函数在外部是不行见的,除非被包含的函数调用了它。

func outerFunction() -> (String) -> String {
    func innerFunction(name: String) -> String {
        return "Welcome, (name)!"
    }
    return innerFunction
}
let welcome = outerFunction()
let message = welcome("Bob")
print(message) // 输出: Welcome, Bob!

嵌套函数捕获的值会被保留在内存中,直到闭包不再被引用。然后确保了鄙人一次履行函数时,之前捕获的值仍旧存在,也无需咱们忧虑内存管理问题

func outerFunction() -> () -> Void {
    var value = 10
    func innerFunction() {
        value += 5
        print(value)
    }
    return innerFunction
}
let closure = outerFunction()
closure() // 输出 15
closure() // 输出 20

3.闭包表达式

3.1 闭包表达式的界说和格局

闭包表达式是一种更为简练的办法界说闭包,通常在需求时进行直接界说和运用,也能够捕获上下文的变量/常量。

  闭包表达式的基本语法包含参数列表、回来箭头和代码块。格局如下:

{ (parameters) -> returnType in
    //statements  
}

举2个例子,分别是 无参数无回来值 和 有参数有回来值(自己能够推导出别的两种写法: 无参数有回来值 和 有参数无回来值)

//无参数无回来值-写法1
let log1: ()->Void = { ()->Void in
    print("closure")
}
//无参数无回来值-写法2
let log2 = { ()->Void in
            print("closure")
        } 
//调用办法
log1()
log2()
//有参数有回来值-写法1
let log1: (_ str:String)->Void = { (str:String)->Void in
    print(str)
    return str
}
//有参数有回来值-写法2
let log2: (_ str:String)->Void = { (str:String)->Void in
    print(str)
    return str
}
//调用办法
let str1 = log1("closure")
let str1 = log2("closure")
3.2 闭包表达式的优化

在 Swift 中,闭包表达式具有简练、灵敏的语法,并支撑一些优化办法。以下是闭包表达式的优化办法:

  • 简化参数和回来类型

能够省掉闭包参数和回来类型的声明,让 Swift 根据上下文进行类型揣度。

// 完好办法
let sum = { (a: Int, b: Int) -> Int in
    return a + b
}
// 优化办法(优化了参数类型声明)
let sumOptimized = { a,b -> Int in
    return a + b
} 

用体系供给的排序函数sorted更直观,由于该函数是比照两个Int参数,回来谁更大谁更小的布尔值判别,即

{ (num1: Int, num2: Int) -> Bool in
    return num1 < num2 
}

所以能够省掉闭包参数和回来类型的声明,如下:

// 完好办法
let sortNumbers = numbers.sorted { (num1:Int, num2:Int) -> Bool in 
    return num1 < num2 
    }
// 优化办法(优化了参数类型和回来类型声明)
let sumSortNumbers = numbers.sorted { num1,num2 in 
    return num1 < num2 
}
  • 单表达式闭包

如果闭包只要一条句子,能够省掉 return 关键字。

// 完好办法
let square = { (number: Int) -> Int in
    return number * number
}
// 优化办法
let squareOptimized = { (number: Int) -> Int in number * number } 
  • 参数名缩写

如果闭包体的参数和回来值能够被主动揣度,那么能够运用 $0, $1, $2, … 来代替闭包中的参数名,然后省掉 in 关键字。(如果闭包体只要一行,而且该行内容能够被主动揣度,不仅能省掉 return 关键字,甚至还能够省掉 in 关键字)

let numbers = [1, 2, 3, 4, 5]
// 完好办法
let mappedNumbers = numbers.map({ (number: Int) -> Int in
    return number * 2
})
// 优化办法(闭包体只要一行,能够省掉 `return` 关键字)
let mappedNumbersOptimized = numbers.map { $0 * 2 }
  • 跟随闭包

在 Swift 中,如果函数的最后一个参数是闭包,而你又需求运用闭包作为函数的参数,那么就能够运用跟随闭包。

跟随闭包是一种在函数调用时编写的闭包表达式,它被写在函数调用的括号之后,跟随闭包的语法允许省掉闭包的参数标签,让函数愈加清晰易读。

func performOperation(_ name:String, _ operation: () -> Void) {
    // 履行操作
    operation()
}
// 完好办法
performOperation("perform",{
    print("Performing operation")
})
// 优化办法
performOperation("perform") {
    print("Performing operation")
} 

若函数只需求闭包表达式一个参数,当运用跟随闭包时,能够把()也省掉掉。

func performOperation(_ operation: () -> Void) {
    // 履行操作
    operation()
}
// 完好办法
performOperation({
    print("Performing operation")
})
// 优化办法
performOperation{
    print("Performing operation")
} 

三、逃逸闭包

逃逸闭包(Escaping Closures)是指在闭包被传递到函数之外的效果域,或许在函数履行完之后才被调用的闭包。(在 Swift 中,闭包默许是非逃逸的,即在函数结束前履行。)

需求运用 @escaping 标记逃逸闭包,以便在函数履行结束后继续存在。

逃逸闭包通常用于异步操作,例如在后台履行任务后履行闭包。

var completionHandlers: [() -> Void] = []
func doSomething(completion: @escaping () -> Void) {
    completionHandlers.append(completion)
}
func executeCompletionHandlers() {
    for handler in completionHandlers {
        handler()
    }
}
// 逃逸闭包
doSomething {
    print("Task completed!")
}
// 履行逃逸闭包
executeCompletionHandlers() // 输出: Task completed!

在这个例子中,doSomething 函数接受一个逃逸闭包作为参数,并将其增加到 completionHandlers 数组中。稍后,通过调用 executeCompletionHandlers 函数,之前增加的闭包会被履行。

四、闭包的运用场景

闭包在 Swift 中有许多运用场景,其间一些包含:

1. 排序操作: 运用闭包对数组进行自界说排序。

let numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
let sortedNumbers = numbers.sorted { $0 < $1 }
print(sortedNumbers) // 输出: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

2. 函数式编程: 使用闭包进行函数式编程,完成高阶函数的功用。

let numbers = [1, 2, 3, 4, 5]
let doubledNumbers = numbers.map { $0 * 2 }
print(doubledNumbers) // 输出: [2, 4, 6, 8, 10]

3. UI 动画 运用闭包完成 UIView 动画的 completion 部分。

UIView.animate(withDuration: 1.0, animations: {
    // 动画效果
}, completion: { _ in
    // 动画完成后履行的闭包
    print("Animation completed!")
})

总结

Swift 中的闭包是一项强壮而灵敏的特性,它为开发者供给了一种简练、高雅的函数式编程办法。深化了解和娴熟运用闭包,将有助于提高 Swift 编程的功率和代码质量。