2016-11-28 55 views
1

Swift數組是指它們是值類型,而類是引用類型,所以我認爲像[SomeClass]會創建一個包含對SomeClass實例的引用的數組。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實例的引用計數應該追加objarray之後是2,而一旦obj = nilarray.removeFirst()被稱爲,既引用被刪除,因此該實例應該被釋放。

但是,這似乎並非如此。沒有數組部分,obj就像它應該發佈一樣。我在這裏錯過了什麼?

ADDED 好像有什麼東西與removeFirst()popLast()和類似的功能怎麼回事。 (可能是一個bug?)

將數組索引處的對象直接設置爲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本身被釋放只釋放。

+0

我想'$ R0'可能持有很強的參考 – Alexander

+0

當你從陣列中,'removeFirst'功能刪除正在返回已刪除的對象。這被'$ R0'強烈地引用,保持你的對象活着。看到我的答案。 – Alexander

回答

1

你的問題是array.removeFirst()在線7正在返回被刪除的對象。 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> 
+0

我想我應該閱讀REPL的工作原理。不知道'$ R0'是你可以在REPL中引用的東西。 – BridgeTheGap

+1

是的,它真的很方便。如果你不把表達式的結果賦值給一個變量(或者用'_'丟棄它),那麼REPL會爲你創建一個新的'$ R'變量。使用過去的價值可能非常方便,您不會想要使用 – Alexander

+0

@BridgeTheGap我回答了您的問題嗎? – Alexander

2

一般來說,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也可能保留強烈的參考,不要依賴它)

+0

很高興知道!我知道遊樂場保留了物體,所以我正在試驗REPL。不知道REPL做了同樣的工作 – BridgeTheGap