返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >Swift中转义闭包示例详解
  • 602
分享到

Swift中转义闭包示例详解

2024-04-02 19:04:59 602人浏览 独家记忆
摘要

目录前言转义与非转义闭包逃离方法将转义关闭付诸行动注意强参考周期内存泄漏背后的原因消除强引用循环概括前言 Swift 是一种非常强大的编程语言,是为 Apple 生态系统开发应用程序

前言

Swift 是一种非常强大的编程语言,是为 Apple 生态系统开发应用程序的首选;iOSMacOS、watchOS 和 tvOS。作为使用 Swift 编写代码的开发人员,我们经常使用闭包;语言的一个重要而重要的章节。

闭包不是初学者开始的主题。然而,这是每个人都必须尽快了解的东西。有很多方面需要了解并了解它们的工作原理。在所有这些中,有一个特定的;转义闭包和@escaping属性。在这篇文章中,我将尽可能简单地解释它们是什么以及它们可能带来的附带影响。

转义与非转义闭包

在谈论转义闭包时,我们总是指作为函数或方法参数提供的闭包。一般来说,我们将提供给方法(或函数)的闭包分为两类:

  1. 在方法执行完成之前调用的闭包。
  2. 在方法执行完成后调用的闭包。

在后一种情况下,我们谈论的是转义闭包;关闭该继续即使电子住后的的xecution方法,直到我们在以后的任何时间在未来给他们打电话。

在前一种情况下,与我上面描述的完全相反,我们称闭包为non-escaping。

直到 Swift 3,默认情况下,所有作为参数传递给方法或函数的闭包都被认为是转义的。自 Swift 3 以来,这不再正确;默认情况下,所有方法都被认为是非转义的,这意味着它们在方法执行完成之前被调用。

以下代码部分演示了一个非转义闭包:


func  add(num1:  Double,

 num2:  Double,

 completion:  (_  result:  Double)  ->  Void)  {

    let  sum  =  num1  +  num2

    completion(sum)

}

所述completion封闭件之前执行代码叶调用的方法,所以这不是一个逸出闭合的情况。

然而,一个闭包是如何从一个方法中逃脱的,所以我们最终得到了与上述情况相反的结果?

逃离方法

为了使闭包成为转义闭包,有必要将对其的引用保留在方法的范围之外,以便我们稍后使用它。看看下面的代码:


class  Demo  {  
    var  result:  Double?
    var  resultHandler:  (()  ->  Void)?
    func  add2(num1:  Double,
              num2:  Double,
              completion:  ()  ->  Void)  {
        resultHandler  =  completion
        result  =  num1  +  num2
    }
}

这里我们有一个result属性,它保存在方法内部发生的加法的结果。但我们也resultHandler有财产;this 保持对completion作为方法参数提供的闭包的引用。

闭包通过以下行从方法中转义:


resultHandler  =  completion

然而,这不是唯一需要的操作,所以我们可以说这completion是一个转义闭包。我们必须明确指出编译器,否则我们将在 Xcode 中看到以下错误:

为了修复它,我们需要用@escaping属性标记闭包。我们将此属性放在闭包名称和分号之后,但在闭包类型之前,如下所示:


func  add2(num1:  Double,
          num2:  Double,
          completion:  @escaping  ()  ->  Void)  {
    ...
}

编译器不再抱怨,completion现在正式成为转义闭包。

将转义关闭付诸行动

让我们在上面的Demo类中再添加两个方法;一个将调用add2(num1:num2:completion:)方法,另一个将调用resultHandler闭包以获得最终结果:


class  Demo  {
    ...
    func  doubleSum(num1:  Double,
                    num2:  Double)  {
        add2(num1:  num1,  num2:  num2)  {
            guard let  result  =  self.result  else  {  return  }
            self.result  =  result  *  2
        }
    }

    func  getResult()  {
        resultHandler?()
    }
}

第一种方法将 add 方法计算的结果加倍。但是,该结果不会翻倍,并且在add2(num1:num2:completion:)我们调用该getResult()方法之前,不会执行该方法中闭包主体内的代码。

这是我们从转义闭包中受益的地方;我们可以在我们的代码中需要的时候以及在合适的时机触发闭包的调用。尽管提供的示例故意过于简单,但在实际项目中,实际优势会变得更加明显和大胆。

注意强参考周期

让我们为Demo类添加最后一个,并实现默认的初始化器和析构器方法:


class  Demo  {
    init()  {
        print("Init")
    }
    deinit  {
        print("Deinit")
    }
    ...
}

init()是Demo初始化实例时调用的第一个方法,deinit也是释放实例之前调用的最后一个方法。我向它们都添加了一个打印命令,以验证它们是否被调用,并且在使用带有上述转义闭包的方法时没有内存泄漏。

注意:当我们尝试通过将对象设置为 nil 来释放它时,可能存在内存泄漏,但该对象仍保留在内存中,因为该对象与其他保持其活动状态的对象之间存在强引用。

现在,让我们添加以下几行来使用上述所有内容:


var  demo:  Demo?  =  Demo()
demo?.doubleSum(num1:  5,  num2:  10)
demo?.getResult()
print((demo?.result!)!)
demo  =  nil

首先,我们初始化类的一个可选实例Demo,以便稍后我们可以将其设为 nil。然后,我们调用该doubleSum(num1:num2:)方法以将作为参数给出的两个数字相加,然后将该结果加倍。但是,正如我之前所说的,在我们调用该getResult()方法之前不会发生这种情况;在方法中实际调用转义闭包的那个add2(num1:num2:completion:)。

最后,我们打印实例中result属性的值demo,并将其demo设为 nil。

*注意:*如上面的代码片段所示,使用感叹号 (!) 强制展开可选值是一种非常糟糕的做法,请不要这样做。我在这里这样做的唯一原因是为了让事情尽可能简单。

以上行将打印以下内容:

Init

30.0

请注意,此处缺少“Deinit”消息!也就是说deinit没有调用该方法,证明制作demo实例nil没有实际结果。看起来,只需几行简单的代码,我们就设法解决了内存泄漏问题。

内存泄漏背后的原因

在我们找到解决内存泄漏的方法之前,有必要了解它发生的原因。为了找到它,让我们退后几步来修改我们之前所做的。

首先,我们使用以下completion行使闭包从方法中逃逸:


resultHandler  =  completion

这条线比看起来更“有罪”,因为它创建了对闭包的强烈引用completion。

注意:闭包是引用类型,就像类一样。

然而,仅凭这一点还不足以产生问题,因为释放demo实例会删除对闭包的引用。真正的麻烦始于doubleSum(num1:num2:)方法内部的闭包主体。

在那里,我们这次通过在使用对象访问属性时捕获**对象来创建另一个从闭包到demo实例的强引用:selfresult


guard let  result  =  self.result  else  {  return  }
self.result  =  result  *  2

当它们都到位时,Demo 实例保持对闭包的强引用,而闭包则是对实例的强引用。这会创建一个保留循环,也称为强引用循环。发生这种情况时,每个引用类型都会使另一个引用类型在内存中保持活动状态,因此它们最终都不会被释放。

请注意,这仅发生在包含带有转义闭包的方法的类中。structs 的情况有所不同,因为它们不是引用而是值类型,并且显式引用self不是强制性的。

消除强引用循环

有两种方法可以避免强引用循环,从而避免内存泄漏。第一个是在我们调用闭包后手动且显式地释放对闭包的引用:


func  getResult()  {
    resultHandler?()
    // Setting nil to resultHandler removes the reference to closure.
    resultHandler  =  nil
}

第二种方法是在闭包的主体中弱**捕获self实例:


func  doubleSum(num1:  Double,
 num2:  Double)  {
    add2(num1:  num1,  num2:  num2)  {  [weak  self]  in
        guard let  result  =  self?.result  else  {  return  }
        self?.result  =  result  *  2
    }
}

[weak self] in在关闭打开后查看添加。有了这个,我们建立了对 Demo 实例的弱引用,因此我们避免了保留循环。请注意,我们将self用作可选值,并在其后加上问号 (?) 符号。

没有必要应用这两种更改以避免强引用循环。无论我们最终选择哪一个,从现在开始,输出也将包含“Deinit”消息。这意味着该demo对象变为 nil,并且我们不再有内存泄漏。

Init

30.0

Deinit

概括

离开这里需要带上一件事,那就是在使用转义闭包时要小心。无论您是实现自己的接受转义闭包作为参数的方法,还是使用具有转义闭包的 API,请始终确保不会以强引用循环结束。在开发应用程序时,内存泄漏是一个很大的“禁忌”,我们当然不希望我们的应用程序在某个时候崩溃或因此被系统终止。另一方面,不要犹豫使用转义闭包;它们提供了可以产生更强大代码的优势。

到此这篇关于Swift中转义闭包的文章就介绍到这了,更多相关Swift转义闭包内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Swift中转义闭包示例详解

本文链接: https://lsjlt.com/news/156354.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Swift中转义闭包示例详解
    目录前言转义与非转义闭包逃离方法将转义关闭付诸行动注意强参考周期内存泄漏背后的原因消除强引用循环概括前言 Swift 是一种非常强大的编程语言,是为 Apple 生态系统开发应用程序...
    99+
    2024-04-02
  • Swift中如何实现转义闭包
    这篇文章主要为大家展示了“Swift中如何实现转义闭包”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Swift中如何实现转义闭包”这篇文章吧。转义与非转义闭包在谈论转义闭包时,我们总是指作为函数...
    99+
    2023-06-25
  • Swift 并发修改Sendable 闭包实例详解
    目录前言使用 Sendable使用泛型和枚举时的隐式一致性从线程安全的实例中抛出错误如何使用Sendable协议要在同一源文件中遵守 Sendable的限制如何使用 @Sendabe...
    99+
    2022-11-13
    Swift 并发修改Sendable 闭包 Sendable 闭包
  • Swift中的HTTP模拟测试示例详解
    目录正文StarWarsAPI 类MockLoader正文 我们已经了解了单个方法如何为通过网络加载请求提供基础。 然而,网络也是开发应用程序时最大的失败点之一,尤其是在单元测试方...
    99+
    2023-02-06
    Swift中的HTTP模拟测试 Swift HTTP
  • Swift 中的 JSON 反序列化示例详解
    目录业界常用的几种方案手动解码方案,如 Unbox(DEPRECATED)阿里开源的 HandyJSON基于 Sourcery 的元编程方案Swift build-in API Co...
    99+
    2024-04-02
  • Python闭包与闭包陷阱举例详解
    目录1 什么是闭包2 闭包示例代码3 什么是闭包陷阱4 闭包陷阱代码实例4.2 第二组代码实例总结1 什么是闭包 在 Python 中,闭包是一种特殊的函数,它能够记住它所在的环境(...
    99+
    2023-01-28
    python中闭包的概念 python闭包详解 Python闭包
  • Swift中的HTTP请求体RequestBodies使用示例详解
    目录正文通用化body空请求体 EmptyBody数据体 DataBodyJSON体 JSONBody表单 FormBody其他Body Other Bodies正文 在进行HTT...
    99+
    2023-02-03
    Swift HTTP请求体Request Bodies Swift HTTP请求体
  • kotlin之闭包案例详解
    闭包,函数式编程福音 先了解函数式编程(Functional Programming) 概念:它属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。函数式编程...
    99+
    2024-04-02
  • python闭包的实例详解
    1、在外部函数中定义内部函数,内部函数包含访问外部函数。即使外部函数的生命周期结束后,内部函数仍然可以访问外部函数变量。 2、外部函数的返回值是内部函数本身。 实例 def ou...
    99+
    2024-04-02
  • Swift进阶教程Mirror反射示例详解
    目录元类型与.selfAnyObjectAnyClassAnytype(Of:)selfself在方法里面的作用Self引用Swift RuntimeMirrorMirror的基本用...
    99+
    2024-04-02
  • Go语言func匿名函数闭包示例详解
    目录前言定义函数也可以作为函数的参数函数作为函数的返回值匿名函数闭包总结前言 今天继续为大家更新Go语言学习记录的文章。 函数是任何一门编程语言最重要的组成部分之一。函数简单理解是一...
    99+
    2024-04-02
  • js中闭包的用法示例
    小编给大家分享一下js中闭包的用法示例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!闭包,其实是一种语言特性,它是指的是程序设计...
    99+
    2024-04-02
  • js中闭包的示例分析
    这篇文章主要介绍了js中闭包的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、说明闭包是具有很多变量和这些变量的环境的表现式(通常是函数),这些变量也是该表现式的一...
    99+
    2023-06-14
  • Python 中闭包与装饰器案例详解
    目录1.Python中一切皆对象2.函数式第一类对象3.函数对象 vs 函数调用4.闭包&LEGB法则5.装饰器&语法糖(syntax sugar)6. 回归问题项目...
    99+
    2024-04-02
  • Swift 中的 async/await ——代码实例详解
    前言 async-await 是在 WWDC 2021 期间的 Swift 5.5 中的结构化并发变化的一部分。Swift 中的并发性意味着允许多段代码同时运行。这是一个非常简化的描述,但它应该让你知道 Swift 中的并发性对你的应用程序...
    99+
    2023-08-17
    swift ios 开发语言
  • react中useEffect闭包的示例分析
    这篇文章主要介绍react中useEffect闭包的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!问题代码看一段因为useEffect导致的闭包问题代码const btn = u...
    99+
    2023-06-15
  • Go语言基础闭包的原理分析示例详解
    目录一. 闭包概述二. 代码演示运行结果代码说明一. 闭包概述 闭包就是解决局部变量不能被外部访问的一种解决方案 闭包是把函数当作返回值的一种应用 二. 代码演示...
    99+
    2024-04-02
  • C++语义copyandswap示例详解
    目录class对象的初始化constructor 构造器constructor overload 构造器重载copy constructor 拷贝构造器拷贝构造器的调用时机自定义拷贝...
    99+
    2022-11-13
    C++语义copy and swap C++语义
  • Vue2 Observer实例dep和闭包中dep区别详解
    目录start1. 依赖收集2. 通知更新思考拓展一拓展二手动通知的案例endstart 此前学习 Vue2 源码。对 Vue 源码中两次出现的new Dep(),不清楚它们的区别,...
    99+
    2022-11-13
    Vue2 Observer与dep闭包 Vue2 闭包
  • Javascript中return与闭包的示例分析
    这篇文章给大家分享的是有关Javascript中return与闭包的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、return的使用案例一:var a=1;...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作