在斯威夫特从字典掠值或按键时,请保留周期 [英] Retain cycle when grabing values or keys from Dictionary in Swift

查看:157
本文介绍了在斯威夫特从字典掠值或按键时,请保留周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我抓住从字典值,并把它们放到阵列,我不能释放内存了。我试图删除阵列和字典中的所有对象,但这些对象仍然存在地方(DEINIT不叫)。

我在玩以下列方式:

 类迈德特{
    让我= 0
    在里面 () {
        的NSLog(初始化)
    }
    DEINIT {
        的NSLog(DEINIT)
    }
}VAR myDictionary:字典<弦乐,迈德特> = [KEY1:迈德特(),KEY2:迈德特()]
//初始化被称为两次//这里的问题是:从字典提取值
VAR myValues​​ =阵列(myDictionary.values​​)
myValues​​ = [] //什么 - 好吧,强引用仍然在字典myDictionary = [:]
//为什么DEINIT不叫?

如果我删除了这两条线路的价值提取,然后DEINIT通常又称为

  VAR anotherDictionary:字典<弦乐,迈德特> = [KEY1:迈德特(),KEY2:迈德特()]
anotherDictionary = [:]
// DEINIT被调用两次VAR myArray的:迈德特[] = [迈德特(),迈德特()]
myArray的= []
// DEINIT被调用两次

我在做什么错在这里?

如何的对象应该不要再需要的时候释放内存的正确方法去除?当键或值从词典(Dictionary.values​​或Dictionary.keys)中提取的问题只发生。

编辑:

我为这种情况下的解决方法。如果我先用,而不是字典和提取键的NSDictionary,然后参加一个for循环值,那么它的工作原理。

  VAR myDictionary:NSDictionary的= [KEY1:迈德特(),KEY2:迈德特()]
//初始化叫两次VAR myKeys:字符串[] = myDictionary.allKeys为String []
VAR myValues​​:迈德特[] = []在myKeys键{
    myValues​​.append(myDictionary [关键]作为迈德特)
}myKeys = []
myDictionary = [:]
myValues​​ = []
// DEINIT现在叫了两次,但我不知道...键

但是,如果我用allValues​​代替allKeys,那么它将无法工作了。

  ...
VAR anotherValues​​ = myDictionary.allValues
anotherValues​​ = []
myDictionary = [:]
// DEINIT不再调用 - 非常可怕的......


解决方案

我不认为这是一个保留周期。我可以简单地通过迭代在字典中的值,甚至没有引入阵列复制本,并没有做任何事情对他们的。我被这个问题玩的时候我注释掉一些code,发现这还不叫DEINIT:

  VAR myDictionary:字典<弦乐,迈德特> = [KEY1:迈德特(),KEY2:迈德特()]
    在myDictionary {(_,项)
        //myValues​​.append(item)
    }
    myDictionary = [:]
    //为什么DEINIT不叫?

如果您取出循环完全如预期DEINIT被调用。如果你把它放回,只是循环,没有做任何事情,那么你没有得到一个DEINIT。

我会说这是某种形式的字典访问的bug;它并不像复杂,因为数组和字典的参考周期。

我可以重现上面这个作为我的循环:

  _为在myDictionary {}

...如果我采取线路输出,它deinits罚款。这是我能找到的最简单/最奇怪的情况。

所以,在你的榜样阵列是一个红色的鲱鱼,我想你已经发现了词典访问的错误。

When I grab values from a Dictionary and put them into Array, I can't release memory any more. I tried to remove all object from Array and Dictionary, but these object still exist somewhere (deinit were not called).

I was playing in the following way:

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???

If I remove these two lines for value extraction, then Deinit is called normally

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

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

What am I doing wrong here?

How the objects should be removed in the proper way to release memory when they don't needed anymore? The problem happens only when keys or values are extracted from Dictionary (Dictionary.values or Dictionary.keys).

EDIT:

I made a workaround for this case. If I use NSDictionary instead of Dictionary and extract keys first and then take values in a for-loop, then it works.

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...

But, if I use allValues instead of allKeys, then it won't work any more.

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

解决方案

I don't think this is a retain cycle. I can reproduce this simply by iterating the values in the Dictionary without even introducing the Array, and without doing anything to them. I was playing with this issue when I commented out some of the code and found that this still doesn't call deinit:

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

If you take out the for loop entirely, deinit is called as expected. If you put it back in—just looping, not doing anything—then you don't get a deinit.

I'd say this is a bug in dictionary access of some kind; it's not as complicated as reference cycles between Array and Dictionary.

I can reproduce the above with this as my for loop:

for _ in myDictionary { }

...and if I take that line out, it deinits fine. That's the simplest/oddest case I could find.

So, the Array in your example is a red herring, and I think you've found a bug with dictionary access.

这篇关于在斯威夫特从字典掠值或按键时,请保留周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆