从两个集合中删除对象的顺序会影响内存管理吗?

时间:2011-11-12 16:24:18

标签: objective-c cocoa-touch memory-management collections

我的算法非常简单。将项添加到缓存。该项目存储在NSMutableArrayNSMutableDictionary中。该数组用作FIFO队列,如果我传递指定的最大大小,我删除最旧的项目,直到大小低于允许的最大值。

当我删除一个项目时,我首先从数组中删除if,然后从字典中删除。然后我遇到问题,因为项目似乎被过度释放(所以调试器说,“似乎”似乎没有指向有效的对象“)。

- (void) addItem:(NSData *)value forKey:(NSString *)key {
    ApiResponseCacheItem *item = [[ApiResponseCacheItem alloc] init];
    item.cacheKey = key;
    item.cacheValue = value;

    [queue addObject:item];
    [item release];
    [dictionary setObject:item forKey:key];

    size += [value length];

    while (size > kMaxCacheSize && [queue count] > 0) {
        ApiResponseCacheItem *oldestItem = [queue objectAtIndex:0];
        size -= [oldestItem.cacheValue length];
        // remove oldest item
        [queue removeObjectAtIndex:0];
        [dictionary removeObjectForKey:oldestItem.cacheKey];
    }
}

现在,我改变了顺序:首先我从字典中删除对象,然后从数组中删除,其他所有内容完全相同。现在一切都很好。

while (size > kMaxCacheSize && [queue count] > 0) {
    ApiResponseCacheItem *oldestItem = [queue objectAtIndex:0];
    size -= [oldestItem.cacheValue length];
    [dictionary removeObjectForKey:oldestItem.cacheKey];
    // remove oldest item
    [queue removeObjectAtIndex:0];
}

请解释。

2 个答案:

答案 0 :(得分:4)

此代码:

[queue addObject:item];
[item release];
[dictionary setObject:item forKey:key];

发布后,您正在使用item。你永远不应该这样做。在[item release];之后移动[dictionary setObject:item forKey:key];

[queue addObject:item];
[dictionary setObject:item forKey:key];
[item release];

答案 1 :(得分:1)

所以,首先@WTP是绝对正确的,你应该接受他的回答。 +1给他。

正确的做法是在发布之后不要触摸'item'。当你已经释放它之后,当然不会将它传递给其他毫无疑问的方法。

但是,话虽如此,如果你想理解为什么命令会对你是否幸存下来产生影响,关键是要记住NSDictionary不保留其密钥,复制它们

所以崩溃序列是这样的:

  1. 您分配/初始化项目 - 保留计数+1
  2. 您将其添加到数组中 - 保留计数+2
  3. 你过早地释放它 - 保留计数+1
  4. 您将其用作词典中的键 - 保留对象的计数 仍然+1(字典制作了一个对象的副本供自己使用)
  5. 将其从数组中删除 - 保留计数0 - 对象消失
  6. 你把悬空指针交给 - [NSMutableDictionary removeObjectForKey:]然后你走了。
  7. 错误没有出现的幸运序列:

    1. 你分配/ init - > 1
    2. 您将其添加到数组中 - > 2
    3. 你发布它 - > 1
    4. 您将其用作关键字 - > 1
    5. 你把它移到removeObjectForKey: - >仍然+1,你避免 崩溃
    6. 您将其从数组中移除 - >保留计数为0
    7. 同样,你应该做@WTP建议的事情。如果你很好奇,这只是背景信息。希望有所帮助。