美文网首页
swift闭包运用

swift闭包运用

作者: fantasy028 | 来源:发表于2023-08-15 17:27 被阅读0次

闭包是swift中相当重要的一个概念,他不仅为swift开发自定义调用执行逻辑提供了方便。同时也是Swift中函数式编程之所以强大的一个重要原因。
这里我们就来探索一下swift闭包的一些用法。
首先从适用场景来讲,闭包基本上可以分为非逃逸闭包和逃逸闭包两种。这个概念在其他语言中是没有的。而swift中引出这个概念,从而让我们能够更好的理解闭包的生命周期。

非逃逸闭包

swift默认的闭包即为非逃逸闭包。其生命周期仅限于闭包参数所在函数的生命周期内有效。一旦超越此作用于,将会导致编译异常。主要体现在两个方面:

  1. 将非逃逸闭包作为参数赋值给对象的一个属性时,会报语法错误提示:
Assigning non-escaping parameter 'xxx' to an @escaping closure
  1. 将非逃逸闭包放在异步执行逻辑中使用则会出现如下语法错误:
Escaping closure captures non-escaping parameter 'xxx'

之所以存在这样的问题,就在与非逃逸闭包的作用域仅限于当前函数本身的生命周期,一旦作为属性或者异步逻辑中的调用存在,将扩大闭包本身的作用于,这与非逃逸闭包的作用于相违背。
例如如下用法即为错误:

func minMax(limit handle: (Int) -> Int) {
        DispatchQueue.main.async {
            _ = handle(1)
        }
}

而正确的用法则为

func minMax(limit handle: (Int) -> Int) -> Int {
        return = handle(1)
}

由此,也就引出了另一个需要讨论的话题逃逸闭包。

逃逸闭包

逃逸闭包可以干啥?简单来说就是非逃逸闭包不能干的两件事,逃逸闭包都能干。此外,非逃逸闭包能做的事情,逃逸闭包当然也能干了。
也就是对于逃逸闭包,可以做如下定义:

@propertyWrapper
class AgeWrapper {
    var wrappedValue: Int {
        get {
            return age
        }
        set {
            age = limitHandle(newValue)
        }
    }
    var age: Int = 0
    var limitHandle: (Int) -> Int
    init(limit handle: @escaping (Int) -> Int) {
        self.limitHandle = handle
        print(handle(199))
    }
}

然后执行如下调用

@AgeWrapper(limit: { max(0, min($0, 121)) }) var age: Int
print("old value -> \(age)")
age = 139
print("new value -> \(age)")

既然如此,是不是说,我们可以直接所有的都用逃逸闭包,而不需要使用非逃逸闭包了呢?当然不是的。试想,如果我们看到的所有暴露的涉及到闭包的函数,看到的都是逃逸闭包,那我们是不是会担心那些原本只作用于当前函数,而在函数结束即结束生命周期的地方,穿入的闭包参数的影响是否会扩大化,从而为编码带来大量的负面效应。因此,在使用闭包的时候,我们应该遵循一个原则:

能用非逃逸闭包就用非逃逸闭包,只有在无法满足这个条件的前提下才用逃逸闭包。

了解了闭包的两种类型之外。我们接下来还要讨论一个概念:自动闭包 @autoclosure。

自动闭包(@autoclosure)

为什么要把自动闭包与非逃逸闭包和逃逸闭包分列出来讲?主要原因在于:

  1. 自动闭包与非逃逸闭包和逃逸闭包在使用上,扩展了概念,使得这类闭包支持表达式方式传参。例如,我们定义了如下函数:
func makeAutoIncrement(closure: @autoclosure () -> Int) -> Int {
        return closure()
    }

在使用上,我们可以使用表达式的形式来传参:

var age = 30
age = makeAutoIncrement(closure: age + 5)
print(age)
age = makeAutoIncrement(closure: age + 3)
print(age)

这使得语法上,更像是传递一个值,但与值传递有所不同的是,自动闭包,会将穿入的数据计算时间后延,从而避免在某些条件下无需执行结果的情况下导致计算耗时。

  1. 自动闭包与非逃逸闭包和逃逸闭包又存在使用上的关联性。这表现在,对于自动闭包,默认其实也是一个非逃逸闭包。而,如果我们在自动闭包修饰符继续使用修饰符@escaping 那么我们将得到一个逃逸的自动闭包。如下:
class WPerson {
        var age: Int
}

func setAutoIncrement(closure: @autoclosure @escaping () -> Int) {
        handle = closure
}

然后进行如下调用

var person = WPerson()
setAutoIncrement(closure: person.age + 3)
person.age = handle()
print(person.age)
person.age = handle()
print(person.age)

我们会发现其打印结果如下:

3
6

变量捕获

在最后一个板块的知识,我们将来了解一下关于闭包中,值的捕获问题。
闭包对与外部变量的捕获,实质上是对变量的一个引用。在内部没有定义同名变量的情况下,闭包中对变量的修改将作用到变量本身。参考示例:

func makeHandle() -> () -> Int {
        var value = 3
        return {
            value = value + 3
            return value
        }
}

我们做如下调用:

let handle = makeHandle()
print(handle())
print(handle())

运行得到如下结果:

6
9

最后,闭包还有许多的语法糖操作,如闭包表达式使用、尾随闭包等,就不在做详细介绍了。

相关文章

  • Swift-闭包

    Swift 闭包 函数 ()->() Swift 中的闭包和 Objective-C 中的 block 类似,闭包...

  • Swift闭包和函数

    函数在Swift中只是一种特殊的闭包,闭包在Swift语言中是一等公民,支持闭包嵌套和闭包传递。Swift中的闭包...

  • swift4 闭包

    swift 闭包 闭包:swift 中 函数是闭包的一种类似于oc的闭包闭包表达式(匿名函数) -- 能够捕获上下...

  • Swift中的闭包

    在Swift中有两种闭包,逃逸闭包(@escaping)和非逃逸闭包(@nonescaping)。从Swift 3...

  • 100 Days of Swift - Day 06 - 闭包(

    100 Days of Swift - Day 06 - 闭包Closures 6.1 闭包 Swift函数也属于...

  • swift学习

    * 闭包 * 闭包作为属性 ```swift // 声明闭包类型 typealias callba...

  • iOS swift 逃逸闭包(@escaping)和非逃逸闭

    iOS swift 逃逸闭包(@escaping)和非逃逸闭包 (@noescaping) 逃逸闭包: 逃逸闭包...

  • iOS&Swift&OC 闭包和Block的相互转化

    一、Swift的闭包 -> OC的block 二、OC的block -> Swift的闭包

  • swift闭包学习

    闭包作为参数 参考 Swift学习之闭包

  • Swift学习笔记(1)

    SWift学习笔记 闭包 闭包表达式 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 ...

网友评论

      本文标题:swift闭包运用

      本文链接:https://www.haomeiwen.com/subject/fxmhmdtx.html