在Swift中从Dictionary中获取值或键时保留循环

Mat*_*jaz 9 arrays dictionary retain-cycle swift

当我从Dictionary中获取值并将它们放入Array时,我无法释放内存.我试图从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???
Run Code Online (Sandbox Code Playgroud)

如果我删除这两行以进行值提取,则会正常调用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
Run Code Online (Sandbox Code Playgroud)

我在这做错了什么?

应该如何以适当的方式删除对象,以便在不再需要时释放内存?只有从Dictionary(Dictionary.values或Dictionary.keys)中提取键或值时才会出现此问题.

编辑:

我为这个案子做了一个解决方法.如果我使用NSDictionary而不是Dictionary并首先提取键然后在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...
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用allValues而不是allKeys,那么它将不再起作用.

...
var anotherValues = myDictionary.allValues
anotherValues = []
myDictionary = [:]
// deinit is not called again - very scary...
Run Code Online (Sandbox Code Playgroud)

Mat*_*son 5

我不认为这是一个保留周期.我可以简单地通过迭代字典中的值来重现这一点,甚至不引入数组,也不需要对它们做任何事情.当我评论出一些代码并发现它仍然没有调用deinit时,我正在玩这个问题:

    var myDictionary:Dictionary<String, MyData> = ["key1":MyData(), "key2":MyData()]
    for (_, item) in myDictionary {
        //myValues.append(item)
    }
    myDictionary = [:]
    // Why Deinit was not called???
Run Code Online (Sandbox Code Playgroud)

如果for完全取出循环,则按预期调用deinit.如果你把它放回 - 只是循环,没有做任何事情 - 那么你就不会得到一个deinit.

我会说这是某种字典访问中的错误; 它没有Array和Dictionary之间的参考周期那么复杂.

我可以将此作为我的for循环重现以上内容:

for _ in myDictionary { }
Run Code Online (Sandbox Code Playgroud)

......如果我把这条线拿出来,那就很好了.这是我能找到的最简单/最奇怪的案例.

所以,你的例子中的数组是一个红色的鲱鱼,我认为你发现了一个字典访问错误.