中的NSMutableDictionary对象突然变得空

问题描述:

更新:中的NSMutableDictionary对象突然变得空

我添加为先检查字典,确实空对象的方法,他们发现:

Nulls in the NSMutableDictionary

没有人见过的东西喜欢这个?这不能由不正确的内存管理引起。请注意,左侧的字典对象树实际上是正确的。

末更新

我加入了一些条目到NSMutableDictionary与ARC启用。添加其中一个之后,突然添加的对象变为空。下面的代码(我扩大它,以确保我没有疯了):

NSMutableDictionary *base = [NSMutableDictionary dictionary]; 

id o = [GAConstant kTRUE]; 
id k = [GAClause parse:@"(x 1 1)"]; 
[base setObject:o forKey:k]; 
NSLog(@"### Added (%@ -> %@): %@", k, o, base); 

o = [GAClause parse:@"(y X)"]; 
k = [GAClause parse:@"(x 2 X)"]; 
[base setObject:o forKey:k]; 
NSLog(@"### Added (%@ -> %@): %@", k, o, base); 

o = [GAConstant kTRUE]; 
k = [GAClause parse:@"(y 3)"]; 
[base setObject:o forKey:k]; 
NSLog(@"### Added (%@ -> %@): %@", k, o, base); 

o = [GAConstant kTRUE]; 
k = [GAClause parse:@"(y 6)"]; 
[base setObject:o forKey:k]; 
NSLog(@"### Added (%@ -> %@): %@", k, o, base); 

下面是输出:

2013-03-25 16:10:33.546 Jungle[1978:11303] ### Added (<GAListClause: 0x75b0dc0> -> <GAConstant: 0x75b12b0>): { 
    "<GAListClause: 0x75b1b00>" = "<GAConstant: 0x75b12b0>"; 
} 
2013-03-25 16:10:33.548 Jungle[1978:11303] ### Added (<GAListClause: 0x75b2870> -> <GAListClause: 0x75b1aa0>): { 
    "<GAListClause: 0x75b2270>" = "<GAListClause: 0x75b1aa0>"; 
    "<GAListClause: 0x75b1b00>" = "<GAConstant: 0x75b12b0>"; 
} 
2013-03-25 16:10:33.549 Jungle[1978:11303] ### Added (<GAListClause: 0x75b2b90> -> <GAConstant: 0x75b12b0>): { 
    "<GAListClause: 0x75b2d80>" = "<GAConstant: 0x75b12b0>"; 
    "<GAListClause: 0x75b2270>" = "<GAListClause: 0x75b1aa0>"; 
    "<GAListClause: 0x75b1b00>" = "<GAConstant: 0x75b12b0>"; 
} 
2013-03-25 16:10:33.550 Jungle[1978:11303] ### Added (<GAListClause: 0x75b2f00> -> <GAConstant: 0x75b12b0>): { 
    "<GAListClause: 0x75b2d80>" = "<GAConstant: 0x75b12b0>"; 
    "<GAListClause: 0x75b2270>" = "<GAListClause: 0x75b1aa0>"; 
    "<GAListClause: 0x75b1b00>" = "<GAConstant: 0x75b12b0>"; 
    "<GAListClause: 0x75b1d60>" = (null); 
} 

的方法[GAConstant kTRUE]初始化并返回一个静态变量。 [GAClause parse:]每次都会返回一个新的解析对象。

很明显为什么k变量的地址与字典的内容不一致:它会复制它们。仍然不清楚null是如何潜入其中的。字典中null的位置会随着每次运行而改变,有时我会得到其中的两个。

看起来像内存管理正在进行,但是什么? ARC在此处启用。

下面就来[GAConstant kTRUE]方法相关的代码:

+ (GAConstant *)kTRUE { 
    static GAConstant *kTRUE = nil; 
    static dispatch_once_t onceToken = 0; 

    dispatch_once(&onceToken, ^{ 
     kTRUE = [[GAConstant alloc] initWithString:@"true"]; 
    }); 

    return kTRUE; 
} 

有时空跨词典波动:

2013-03-25 17:09:16.426 Jungle[2294:11303] ### Added (<GAListClause: 0x7182ce0> -> <GAConstant: 0x7183430>): { 
    "<GAListClause: 0x7183a30>" = "<GAConstant: 0x7183430>"; 
} 
2013-03-25 17:09:16.428 Jungle[2294:11303] ### Added (<GAListClause: 0x75467b0> -> <GAListClause: 0x71839d0>): { 
    "<GAListClause: 0x7546a30>" = (null); 
    "<GAListClause: 0x7183a30>" = "<GAConstant: 0x7183430>"; 
} 
2013-03-25 17:09:16.429 Jungle[2294:11303] ### Added (<GAListClause: 0x7546cd0> -> <GAConstant: 0x7183430>): { 
    "<GAListClause: 0x7546ec0>" = "<GAConstant: 0x7183430>"; 
    "<GAListClause: 0x7546a30>" = "<GAListClause: 0x71839d0>"; 
    "<GAListClause: 0x7183a30>" = "<GAConstant: 0x7183430>"; 
} 
2013-03-25 17:09:16.430 Jungle[2294:11303] ### Added (<GAListClause: 0x7547040> -> <GAConstant: 0x7183430>): { 
    "<GAListClause: 0x75470f0>" = (null); 
    "<GAListClause: 0x7546ec0>" = "<GAConstant: 0x7183430>"; 
    "<GAListClause: 0x7546a30>" = "<GAListClause: 0x71839d0>"; 
    "<GAListClause: 0x7183a30>" = "<GAConstant: 0x7183430>"; 
} 

下面是它看起来像在调试器:

Debugger

+0

只是猜测,使用'[base setObject:[o copy] forKey:[k copy]];' – 2013-03-25 16:38:55

+0

@AnoopVaidya这不是我正在寻找的行为 - 我想存储原件,而不是副本 – 2013-03-25 16:40:26

+1

[GAConstant kTRUE]是否正确保存到静态变量?那是否是一个强有力的参考?我怀疑你的字典中的无效值实际上是一个'[NSNull null]'。你的代码中实际使用'NSNull'的地方是否存在?也许有一些碰撞发生? ''[NSObject hash]'和'[NSObject isEqual:]'在'GAClause'上正确实现了吗? – Sulthan 2013-03-25 16:47:59

你的问题很严重TRANGE。总之,调试器显示您的字典正确,但objectForKey返回nil

我在最后一个小时想到了这一点,我很确定我只知道这种情况发生的可能性 - 不正确的hashisEqual:方法。

特别是,我认为isEqual:方法是不对称的。换句话说,如果我们有

id k = [GAClause parse:@"(x 1 1)"]; 

然后

[k isEqual:k] 

并不一定是真实的。

然后,如果您得到您的字典键并尝试查找它们的值(与[NSDictionary description]相同),则无法找到这些值。

我相信你应该把你的断点/ NSLog转换成isEqual并观察比较值时发生了什么。

另请注意,字典键被复制,因此在复制过程中可能会出现相等问题。

+0

*中的更新*注意,字典密钥已被复制,因此在复制期间可能会出现相等问题* - 情况就是如此。我回顾了'isEqual:'和'copyWithZone:'实现,发现它们提供的结果不一致。 – 2013-03-26 12:23:35

+1

来自[meta post](https://meta.*.com/a/303309/5555803):) – 2017-08-06 18:03:41