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

维沙尔·辛格

我对闭包的理解是,它会强烈地捕获所有直接引用的对象,而不管对象变量是声明的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条评论
登录后参与评论

相关文章

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Java

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

来自分类Dev

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

来自分类Java

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

来自分类Dev

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

来自分类Java

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

来自分类Java

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Javascript

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Dev

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

来自分类Java

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

Related 相关文章

  1. 1

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

  2. 2

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

  3. 3

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

  4. 4

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

  5. 5

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

  6. 6

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

  7. 7

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

  8. 8

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

  9. 9

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

  10. 10

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

  11. 11

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

  12. 12

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

  13. 13

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

  14. 14

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

  15. 15

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

  16. 16

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

  17. 17

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

  18. 18

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

  19. 19

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

  20. 20

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

  21. 21

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

  22. 22

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

  23. 23

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

  24. 24

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

  25. 25

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

  26. 26

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

  27. 27

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

  28. 28

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

  29. 29

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

热门标签

归档