9

ディクショナリから値を取得して配列に入れると、メモリを解放できなくなります。Array と Dictionary からすべてのオブジェクトを削除しようとしましたが、これらのオブジェクトはまだどこかに存在しています (deinit が呼び出されていません)。

以下の方法で遊んでいました。

class MyData {
    let i = 0
    init () {
        NSLog("Init")
    }
    deinit {
        NSLog("Deinit")
    }
}

var myDictionary:Dictionary<String, MyData> = ["key1":MyData(), "key2":MyData()] 
// Init was called twice

// here is the problem: extract values from Dictionary
var myValues = Array(myDictionary.values)
myValues = []  // nothing - ok, strong references are still in the dictionary

myDictionary = [:] 
// Why Deinit was not called???

値を抽出するためにこれら 2 行を削除すると、Deinit が正常に呼び出されます。

var anotherDictionary:Dictionary<String, MyData> = ["key1":MyData(), "key2":MyData()]
anotherDictionary = [:] 
// Deinit is called twice

var myArray:MyData[] = [MyData(), MyData()]
myArray = []  
// Deinit is called twice

ここで何が間違っていますか?

オブジェクトが不要になったときにメモリを解放するために、オブジェクトを適切な方法で削除するにはどうすればよいですか? この問題は、ディクショナリ (Dictionary.values または Dictionary.keys) からキーまたは値が抽出された場合にのみ発生します。

編集:

この場合の回避策を作成しました。Dictionary の代わりに NSDictionary を使用し、最初にキーを抽出してから for ループで値を取得すると、機能します。

var myDictionary:NSDictionary = ["key1":MyData(), "key2":MyData()] 
// called Init twice

var myKeys:String[] = myDictionary.allKeys as String[]
var myValues:MyData[] = []

for key in myKeys {
    myValues.append(myDictionary[key] as MyData)
}

myKeys = []
myDictionary = [:]
myValues = []
// Deinit is now called twice, but I'm not sure about keys...

しかし、allKeys の代わりに allValues を使用すると、機能しなくなります。

...
var anotherValues = myDictionary.allValues
anotherValues = []
myDictionary = [:]
// deinit is not called again - very scary...
4

1 に答える 1