Swift 数组干扰弱变量的释放

Swift array messing with the release of weak variables

Swift 数组是值类型,而 类 是引用类型,所以我认为 [SomeClass] 之类的东西会创建一个包含对 [=14= 的引用的数组] 实例。

但是,在 Swift REPL 中,会发生以下情况:

  1> class SomeClass {}
  2> var obj: SomeClass? = SomeClass()
obj: SomeClass? = 0x0000000101100050
  3> weak var weakObj = obj
weakObj: SomeClass? = 0x0000000101100050
  4> var array = [SomeClass?]()
array: [SomeClass?] = 0 values
  5> array.append(obj)
  6> print(obj, weakObj)
Optional(SomeClass) Optional(SomeClass)
  7> array.removeFirst()
$R0: SomeClass? = 0x0000000101100050
  8> obj = nil
  9> print(obj, weakObj)
nil Optional(SomeClass)
 10> print(array)
[]
 11> print(Unmanaged.passUnretained(weakObj!).toOpaque())
0x0000000101100050

我认为 0x0000000101100050 处的实例的引用计数在将 obj 附加到 array 之后应该是 2,一旦 obj = nilarray.removeFirst()被调用,两个引用都被删除,因此实例应该被释放。

然而,情况似乎并非如此。没有数组部分, obj 会像它应该的那样被释放。我在这里错过了什么?

已添加 似乎 removeFirst()popLast() 和类似函数发生了一些事情。 (可能是错误?)

将数组索引处的对象直接设置为 nil 就可以了。

 102> obj = SomeClass()
 103> (weakObj, array) = (obj, [obj])
 104> print(obj, weakObj, array)
Optional(SomeClass) Optional(SomeClass) Optional([Optional(SomeClass)])
 105> obj = nil
 106> array?[0] = nil
$R14: ()? = nil
 107> print(obj, weakObj, array)
nil nil Optional([nil])

但是,当使用removeLast()popLast()时,weakObj只有在array本身被释放时才会被释放。

一般来说,REPL(或 Playground)不是试验 Swift ARC 工作原理的好地方。

尝试将您的代码作为 macOS 的命令行项目:

import Foundation

class SomeClass {}
var obj: SomeClass? = SomeClass()
weak var weakObj = obj
var array = [SomeClass?]()
array.append(obj)
print(obj, weakObj) //->Optional(SwiftArrayARC.SomeClass) Optional(SwiftArrayARC.SomeClass)
array.removeFirst()
obj = nil
print(obj, weakObj) //->nil nil
print(array) //->[]
print(Unmanaged.passUnretained(weakObj!).toOpaque()) //=>fatal error: unexpectedly found nil while unwrapping an Optional value

这不正是你所期待的吗?

REPL 可能会为每一行的结果保留强引用,以便您稍后使用它们,因此,在 REPL 环境中,您无法获得与实际应用程序中显示的完全相同的行为。

创建一个简单的命令行项目并在其中进行试验。 (注意:LLDB 也可能保留强引用。不要依赖它。)

您的问题是第 7 行的 array.removeFirst() 正在返回已删除的对象。 repl 为您将此分配给 $R0,这是使您的对象保持活动状态的强引用。

如果您使用 _ =:

显式丢弃结果,您的代码将按预期运行
Welcome to Apple Swift version 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1). Type :help for assistance.
  1> class SomeClass {}
  2> var obj: SomeClass? = SomeClass()
obj: SomeClass? = 0x00000001006005b0
  3> weak var weakObj = obj
weakObj: SomeClass? = 0x00000001006005b0
  4> var array = [SomeClass?]()
array: [SomeClass?] = 0 values
  5> array.append(obj)
  6> print(obj, weakObj)
Optional(SomeClass) Optional(SomeClass)
  7> _ = array.removeFirst()
  8> obj = nil
  9> print(obj, weakObj)
nil nil
 10> print(array)
[]
 11> print(Unmanaged.passUnretained(weakObj!).toOpaque())
fatal error: unexpectedly found nil while unwrapping an Optional value
2016-11-27 20:58:42.066831 repl_swift[62143:10516084] fatal error: unexpectedly found nil while unwrapping an Optional value
Current stack trace:
0    libswiftCore.dylib                 0x00000001002bccc0 swift_reportError + 132
1    libswiftCore.dylib                 0x00000001002da070 _swift_stdlib_reportFatalError + 61
2    libswiftCore.dylib                 0x00000001000d00a0 specialized specialized StaticString.withUTF8Buffer<A> ((UnsafeBufferPointer<UInt8>) -> A) -> A + 355
3    libswiftCore.dylib                 0x000000010024c210 partial apply for (_fatalErrorMessage(StaticString, StaticString, StaticString, UInt, flags : UInt32) -> Never).(closure #2) + 109
4    libswiftCore.dylib                 0x00000001000d00a0 specialized specialized StaticString.withUTF8Buffer<A> ((UnsafeBufferPointer<UInt8>) -> A) -> A + 355
5    libswiftCore.dylib                 0x00000001002043d0 specialized _fatalErrorMessage(StaticString, StaticString, StaticString, UInt, flags : UInt32) -> Never + 96
7    repl_swift                         0x0000000100001420 main + 0
8    libdyld.dylib                      0x00007fffaaec7254 start + 1
Execution interrupted. Enter code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
 12>