1

更新:

我添加了一个方法来检查字典中的空对象,并且确实找到了它们:

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;
}

有时 null 在字典中波动:

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>";
}

这是它在调试器中的样子:

调试器

4

1 回答 1

6

你的问题很奇怪。总之,调试器将您的字典显示为正确但objectForKey返回nil.

我在过去的一个小时里一直在考虑这个问题,我很确定我只知道这种情况发生的一种可能性——不正确hashisEqual:方法。

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

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

然后

[k isEqual:k]

不一定是真的。

然后,如果您获取字典键并尝试查找它们的值(也是[NSDictionary description]如此),则找不到这些值。

我相信您应该将断点 /NSLog放入isEqual并观察比较值时发生的情况。

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

于 2013-03-25T20:21:47.890 回答