Порядок удаления объекта из двух коллекций влияет на управление памятью? - PullRequest
1 голос
/ 12 ноября 2011

Мой алгоритм довольно прост. Добавить элемент в кеш. Элемент хранится как в NSMutableArray, так и в NSMutableDictionary. Массив служит в качестве очереди 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 ]

4 голосов
/ 12 ноября 2011

Этот код:

[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 голос
/ 12 ноября 2011

Итак, прежде всего @WTP абсолютно прав, и вы должны принять его ответ. +1 к нему.

Правильнее всего не касаться «предмета» после того, как вы его отпустили. И, конечно, не передавайте его другим ничего не подозревающим методам после того, как вы уже выпустили его.

Но, сказав, что, если вы хотите понять, почему порядок изменил то, пережили ли вы ошибку или нет, нужно помнить, что NSDictionary не сохраняет свои ключи, он копирует их .

Итак, последовательность сбоя была такой:

  1. Вы выделяете / инициализируете предмет - Сохраняете счет + 1
  2. Вы добавляете его в массив - Сохранить счет + 2
  3. Вы отпускаете его преждевременно - Сохраните счет + 1
  4. Вы используете его в качестве ключа в словаре - сохранить счет вашего объекта +1 (словарь сделал копию объекта для собственного использования)
  5. Вы удаляете его из массива - Сохранить счет 0 - объект пропал
  6. Вы передаете висячий указатель на - [NSMutableDictionary удалитьObjectForKey:] и вниз.

Счастливая последовательность, где ошибка не появилась:

  1. Вы выделяете / init -> + 1
  2. Вы добавляете его в массив -> + 2
  3. Вы отпускаете его -> + 1
  4. Вы используете его в качестве ключа -> + 1
  5. Вы передаете его, чтобы удалитьObjectForKey: -> Еще +1, и вы избежали крушение
  6. Вы удаляете его из массива -> Число сохраняемых значений равно 0

Опять же, вы должны делать то, что советовал @WTP. Это просто справочная информация, если вам интересно. Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...