我们是否需要在快速关闭中为弱变量显式使用捕获列表?

维沙尔·辛格

我对闭包的理解是,它会强烈地捕获所有直接引用的对象,而不管对象变量是声明的weak还是strong在闭包之外,如果我们弱捕获它们,那么我们需要显式定义一个捕获列表并weak在其中标记它们捕获列表。

obj?.callback = { [weak obj] in
    obj?.perform()
}

但是在我的测试中,我发现如果变量已经weak在闭包之外,那么我们就不需要使用捕获列表来弱捕获它了。

class Foo {
    var callback: (() -> ())?
    
    init() {
        weak var weakSelf = self
        callback = {
            weakSelf?.perform()
        }
//        is above equivalent to below in terms of memory management?
//        callback = { [weak self] in
//            self?.perform()
//        }
    }
    
    func perform() {
        print("perform")
    }
    
    deinit {
        print("deinit")
    }
}

let foo = Foo() // prints "deinit foo"

上面的代码段没有创建任何保留周期。这是否意味着如果变量已经声明,我们不需要在捕获列表中显式地捕获对象变量,weak并且捕获列表只是在语法上优于weak在闭包中使用它们之前创建变量。

罗伯·纳皮尔

有点,在这个具体的例子中,但你需要非常小心你如何看待正在发生的事情。

首先,是的,这是相同的。我们可以通过生成 SIL ( swiftc -emit-sil main.swift) 来判断这一点。除了selfvs的名称不同外weakSelf,它们生成完全相同的未优化 SIL。为了更清楚,我将更改捕获列表中变量的名称(这只是重命名,不会改变行为):

弱自我

    weak var weakSelf = self
    callback = {
        weakSelf?.perform()
    }

弱自我

    callback = { [weak weakSelf = self] in
        weakSelf?.perform()
    }

比较它们

$ swiftc -emit-sil weakSelf.swift > weakSelf.sil
$ swiftc -emit-sil weak_self.swift > weak_self.sil
$ diff -c weakSelf.sil weak_self.sil

*** weakSelf.sil    2022-03-27 10:58:13.000000000 -0400
--- weak_self.sil   2022-03-27 11:01:22.000000000 -0400
***************
*** 102,108 ****

  // Foo.init()
  sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self"                                      // users: %15, %8, %7, %2, %22, %1
  bb0(%0 : $Foo):
    debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
    %2 = ref_element_addr %0 : $Foo, #Foo.callback  // user: %4
--- 102,108 ----

  // Foo.init()
  sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self"                                      // users: %8, %7, %15, %2, %22, %1
  bb0(%0 : $Foo):
    debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
    %2 = ref_element_addr %0 : $Foo, #Foo.callback  // user: %4

除了用户评论的顺序之外self,它们是相同的。

但是要非常非常小心地处理这些知识。恰好是真的,因为存在对self其他地方的强烈引用。在这条路上走得太远会导致混乱。例如,考虑以下两种方法:

// Version 1
weak var weakObject = Object()
let callback = {
    weakObject?.run()
}
callback()


// Version 2
var weakObject = Object()
let callback = { [weak weakObject] in
    weakObject?.run()
}
callback()

这些行为根本不一样。在第一个版本中,weakObject在创建时已经发布callback,所以callback()什么也不做。编译器会对此产生警告,因此在大多数情况下,这是一个不太可能创建的错误,但通常你应该在捕获列表中进行弱捕获,以便它尽可能接近闭包创建,并赢得不小心被意外释放。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Java

我们是否需要在春豆静态字段?

来自分类Java

我们需要在Java 8来检查流是否为空,而不是迭代

来自分类Javascript

我们是否需要在IIFE中包装ES6代码?

来自分类Java

我们是否需要在ArrayList上使用迭代器?

来自分类Java

我是否需要显式关闭连接?

来自分类Java

为什么我们需要Java中的弱引用

来自分类Dev

我们是否需要在HTML5中为<link>输入type =“ text / css”

来自分类Dev

我们是否应该继续明确地将变量捕获为iOS中的弱变量

来自分类Dev

为什么我们需要在MSIL中显式调用父构造函数?

来自分类Dev

斯威夫特:我们需要在使用变量之前声明一个变量吗?

来自分类Dev

我们是否需要显式关闭在方法参数中作为匿名类传递的Streams或Readers?

来自分类Dev

我们是否需要在天蓝色函数中照顾垃圾收集?

来自分类Dev

如果我们在flutter中使用ImagePicker库,是否需要显式实现ImageCache?

来自分类Dev

我们是否需要在BCrypt中使用固定盐?

来自分类Dev

我们是否需要在集群中的每个节点上运行nodetool修复?

来自分类Dev

以太坊/坚实度:我们需要在合同中实现自己的“余额”变量吗?

来自分类Dev

我们是否需要在Solr Search的搜索值中包含斜杠(/)的转义字符

来自分类Dev

为什么我们需要在链接列表中填充数据?

来自分类Dev

在CBOW模型中,我们是否需要在“隐藏层”取平均值?

来自分类Dev

我们是否需要在.net 4.0或4.5中使用此关键字

来自分类Dev

我们是否需要在cuda编程中设置网格数?

来自分类Dev

我们是否需要在构建时针对phonegap中的每个不同平台更改代码?

来自分类Dev

我们是否需要在android中为sqlite表创建索引?

来自分类Dev

我们需要在Asp.net中为网站页面创建Class文件吗?

来自分类Dev

我们是否需要为运行公共ELB的子网显式设置路由表?

来自分类Dev

我们是否应该使用显式类型在Java中实例化地图对象?

来自分类Dev

在Selenium WebDriver中,为什么我们需要在使用显式等待之前将隐式等待设置为0

来自分类Dev

我们是否需要在 MySQL 中的给定列上使用多个索引?

来自分类Dev

我们是否需要在不使用计费的情况下关闭 GCP 虚拟机,因为它是按小时计算的?

Related 相关文章

  1. 1

    我们是否需要在春豆静态字段?

  2. 2

    我们需要在Java 8来检查流是否为空,而不是迭代

  3. 3

    我们是否需要在IIFE中包装ES6代码?

  4. 4

    我们是否需要在ArrayList上使用迭代器?

  5. 5

    我是否需要显式关闭连接?

  6. 6

    为什么我们需要Java中的弱引用

  7. 7

    我们是否需要在HTML5中为<link>输入type =“ text / css”

  8. 8

    我们是否应该继续明确地将变量捕获为iOS中的弱变量

  9. 9

    为什么我们需要在MSIL中显式调用父构造函数?

  10. 10

    斯威夫特:我们需要在使用变量之前声明一个变量吗?

  11. 11

    我们是否需要显式关闭在方法参数中作为匿名类传递的Streams或Readers?

  12. 12

    我们是否需要在天蓝色函数中照顾垃圾收集?

  13. 13

    如果我们在flutter中使用ImagePicker库,是否需要显式实现ImageCache?

  14. 14

    我们是否需要在BCrypt中使用固定盐?

  15. 15

    我们是否需要在集群中的每个节点上运行nodetool修复?

  16. 16

    以太坊/坚实度:我们需要在合同中实现自己的“余额”变量吗?

  17. 17

    我们是否需要在Solr Search的搜索值中包含斜杠(/)的转义字符

  18. 18

    为什么我们需要在链接列表中填充数据?

  19. 19

    在CBOW模型中,我们是否需要在“隐藏层”取平均值?

  20. 20

    我们是否需要在.net 4.0或4.5中使用此关键字

  21. 21

    我们是否需要在cuda编程中设置网格数?

  22. 22

    我们是否需要在构建时针对phonegap中的每个不同平台更改代码?

  23. 23

    我们是否需要在android中为sqlite表创建索引?

  24. 24

    我们需要在Asp.net中为网站页面创建Class文件吗?

  25. 25

    我们是否需要为运行公共ELB的子网显式设置路由表?

  26. 26

    我们是否应该使用显式类型在Java中实例化地图对象?

  27. 27

    在Selenium WebDriver中,为什么我们需要在使用显式等待之前将隐式等待设置为0

  28. 28

    我们是否需要在 MySQL 中的给定列上使用多个索引?

  29. 29

    我们是否需要在不使用计费的情况下关闭 GCP 虚拟机,因为它是按小时计算的?

热门标签

归档