【发布时间】:2020-03-20 22:04:09
【问题描述】:
您可以逐字复制这个游乐场:
var closures=[() -> Void]()
class Thing {
let name: String
init(_ name: String) { self.name=name }
}
class RefThingWrapper {
let thing: Thing
init(_ t: Thing) {
self.thing=t
closures.append { [thing, weak self] in // Even though `thing` captured strongly, `self` could still get deallocated.
print((self == nil) ? "`self` deallocated" : "`self` not deallocated")
print(thing.name) // Decided to use `thing` within closure to eliminate any chance of optimizations affecting the test results — which I found when I captured `self` strongly without using it.
}
}
}
struct ValThingWrapper {
let thing: Thing
init(_ t: Thing) {
self.thing=t
closures.append { [weak thing] in
print((thing == nil) ? "`thing` deallocated" : "`thing` not deallocated")
}
}
}
var wrapper=Optional(RefThingWrapper(Thing("Thing 1"))) // Test with reference type.
//var wrapper=Optional(ValThingWrapper(Thing("Thing 1"))) // Test with value type.
closures[0]()
wrapper=nil
closures[0]()
它演示了self 的属性(self 是引用类型还是值类型)如何在闭包中独立于self 被捕获。按原样运行程序演示了在 self 被释放后存在的捕获属性。使用值类型包装器进行的测试表明,如果被弱捕获,一旦引用的值实例被释放,该实例将被释放。
我不确定这是否可行,因为一开始创建闭包时,我忘记初始化我正在捕获的属性。所以编译器抱怨——在捕获列表中——'self' used before all stored properties are initialized。所以我认为self 被隐式捕获,只有在深入挖掘之后才会发现。
这是否记录在某处?我找到了 Joe Groff 提出的this post:
对于类的“让”属性,建议具有 默认情况下,闭包以这种方式直接捕获 属性 而不是捕获“自我”(并且可能允许引用它们 没有“自我”,因为“自我”不会参与形成的任何循环 这样)。
这是 2015 年的事,我没有发现讨论中产生的任何已实施的提案。是否有任何权威来源可以传达这种行为?
【问题讨论】:
-
是的,将值预先捕获到捕获列表中的能力鲜为人知。请注意,这与闭包捕获不同;其实恰恰相反,是一种避免闭包捕获的方法。
-
看看我使用这个的例子:github.com/mattneub/Programming-iOS-Book-Examples/blob/master/… 见第 41 行。如果我们没有预先捕获,我们将做与我正在尝试做的完全相反的事情。我们想要捕获
self.center现在的值,而不是当这个闭包被调用时它的值。 -
@matt 哇。不记得以前在捕获列表中看到过分配。查看语法,预先捕获一个值类型看起来大致是我想象的样子。使用引用类型并且没有
=符号,self是否被隐式捕获对我来说似乎模棱两可。但事后看来,如果您可以捕获一个值类型而不捕获self以及它,这似乎很自然,引用类型也将遵循同样的情况。
标签: swift