从`deinit`中走私`self`
Posted
技术标签:
【中文标题】从`deinit`中走私`self`【英文标题】:Smuggling `self` out of a `deinit` 【发布时间】:2020-01-14 16:01:03 【问题描述】:如果我通过将self
从我的deinit
中偷运出来,将其分配给某个外部强引用,会发生什么情况?下面这段代码显然格式不正确:
class C: CustomStringConvertible
let s = "abc"
var description: String
return "C(id: \(ObjectIdentifier(self)), s: \(s))"
deinit
print("deinit")
globalObject = self
var globalObject: C!
do
let localObject = C()
print("localObject: \(localObject)")
print("end of `do`")
print("globalObject: \(globalObject!)")
您不能只是从deinit
的中间“改变主意”来取消对象的初始化。但有趣的是,这段代码是不确定的,它有时会成功完成,打印:
localObject: C(id: ObjectIdentifier(0x00007f9063f00960), s: abc)
end of `do`
deinit
globalObject: C(id: ObjectIdentifier(0x00007f9063f00960), s: abc)
我正在使用 Code Runner 运行它,它只是使用 swiftc
运行单个文件 Swift 脚本。所以这里没有意外的 Playground 拥有的引用。
不确定性从何而来?
【问题讨论】:
我在 Playground 和 Repl.It 上运行了十次,每次崩溃。您需要运行多少次才能成功完成? Idk,大约十分之一。swiftc --version
给出Apple Swift version 5.1 (swiftlang-1100.0.212.5 clang-1100.0.28.2) Target: x86_64-apple-darwin19.0.0
我用的是5.0.1,又跑了几次,还是不行。似乎是特定于 5.1 那么...
forums.swift.org/t/retain-self-in-deinit/6365 和 ***.com/questions/49117750/…
@J.Doe 我知道这是不合法的。我只是不知道为什么这不会总是崩溃。
【参考方案1】:
这不是答案,但评论太长了:
有趣的是,我只是附加了:
for _ in 1...1000000
print("intermediate: \(globalObject!)")
print("globalObject: \(globalObject!)")
然后:
swiftc test.swift
for ((i = 0; i < 10000; i++)); do
./test | fgrep globalObject
done
我得到的是(这 10000 次运行中只有一次):
致命错误:对象被保留太多次a(44854,0x10a92f5c0) malloc: 已释放对象 0x7fcc1ec02b98 的校验和不正确:可能在被释放后修改。
损坏值:0x7ffffffe00000000
test(44854,0x10a92f5c0) malloc: *** 在 malloc_error_break 中设置断点进行调试
globalObject: C(id: ObjectIdentifier(0x00007f7f452006c0), s: abc)
test(61212,0x114d7e5c0) malloc: 已释放对象 0x7fe063e00008 的校验和不正确:释放后可能已修改。
损坏值:0x4ffffffe00000000
test(61212,0x114d7e5c0) malloc: *** 在 malloc_error_break 中设置断点进行调试
下一次运行:
test(7016,0x10682d5c0) malloc: tiny_free_list_remove_ptr: 内部不变量损坏(prev 的下一个 ptr):ptr=0x7fb2e0805fd0, prev_next=0x7f92e0805fd0
这似乎是某种竞争条件,但我不知道是谁在这里产生线程。 顺便说一句:
swiftc -version
Apple Swift version 5.0.1 (swiftlang-1001.0.82.4 clang-1001.0.46.5)
Target: x86_64-apple-darwin18.7.0
【讨论】:
以上是关于从`deinit`中走私`self`的主要内容,如果未能解决你的问题,请参考以下文章
从内存中删除 UIView 时,快速 deinit 方法不起作用
是否应该重写 deinit 以删除 Swift 中的观察者?