Проблема анализатора: потенциальная утечка объекта, выделенного в строке 25 и сохраненного в oneCopy.

Я обновил Xcode и получил множество предупреждений анализатора, например:

Возможная утечка объекта, выделенного в строке 25 и сохраненного в oneCopy.

Может кто-то указать мне верное направление?

@implementation NSDictionary(DeepMutableCopy)
-(NSMutableDictionary *)mutableDeepCopy
{
    NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
    NSArray *keys = [self allKeys];
    for (id key in keys)
    {
        id oneValue = [self valueForKey:key];
        id oneCopy = nil;

        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])
            oneCopy = [oneValue mutableDeepCopy];
        else if ([oneValue respondsToSelector:@selector(mutableCopy)])
            oneCopy = [oneValue mutableCopy];
        if (oneCopy == nil)
            oneCopy = [oneValue copy];
        [ret setValue:oneCopy forKey:key];
    }
    return ret;
}
@end

Снимок экрана с номерами строк:
введите здесь описание изображения

#import "NSDictionary-DeepMutableCopy.h"


@implementation NSDictionary(DeepMutableCopy)
-(NSMutableDictionary *)mutableDeepCopy
{
    //NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
    NSMutableDictionary *ret = [NSMutableDictionary dictionaryWithCapacity:[self count]];
    NSArray *keys = [self allKeys];
    for (id key in keys)
    {
        id oneValue = [self valueForKey:key];
        id oneCopy = nil;

        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])
            oneCopy = [oneValue mutableDeepCopy];
        else if ([oneValue respondsToSelector:@selector(mutableCopy)])
            oneCopy = [oneValue mutableCopy];
        if (oneCopy == nil)
            oneCopy = [oneValue copy];
        [ret setValue:oneCopy forKey:key];
        [oneCopy release];
    }
    return ret;

}
@end

person Jules    schedule 09.11.2011    source источник
comment
Можете ли вы сказать нам, какая строка является строкой 25?   -  person Alexsander Akers    schedule 10.11.2011
comment
Смотрите редактирование, я также получаю дополнительную ошибку.   -  person Jules    schedule 10.11.2011


Ответы (2)


Сначала решая свою вторую проблему, вместо [[NSMutableDictionary alloc] initWithCapacity:[self count]] вы можете использовать [NSMutableDictionary dictionaryWithCapacity:[self count]], который вернет автоматически выпущенный объект, и вам придется сохранить его самостоятельно в вызывающем коде.

С другой стороны, вы можете переименовать свой метод, чтобы он начинался со слова «копировать», если вы хотите, чтобы он возвращал сохраненный объект, а не выдавал ошибки — что, я думаю, именно то, что вы хотите сделать в этом случае . Остальная часть моего ответа предполагает, что вы выбрали этот путь.

Мой первоначальный ответ был следующим: вы не выпускаете oneCopy в конце каждой итерации. Попробуйте добавить [oneCopy release]; сразу после [ret setValue:oneCopy forKey:key];.

Однако, поскольку Александр Акерс указывает, что компилятор считает, что -mutableDeepCopy имеет 0 ссылок. Итак, если вы переименуете, как было предложено выше, и включите [oneCopy release], как я первоначально предложил, это должно решить обе проблемы. Если это не так, обязательно ознакомьтесь с некоторыми другими решениями в вопросе, на который он ссылался.

Пример:

@implementation NSDictionary(DeepMutableCopy)
-(NSMutableDictionary *)copyWithDeepCopiedValues
{
    NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithCapacity:[self count]];

    NSArray *keys = [self allKeys];
    for (id key in keys)
    {
        id oneValue = [self valueForKey:key];
        id oneCopy = nil;

        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])
            oneCopy = [oneValue copyWithDeepCopiedValues];
        else if ([oneValue respondsToSelector:@selector(mutableCopy)])
            oneCopy = [oneValue mutableCopy];
        if (oneCopy == nil)
            oneCopy = [oneValue copy];
        [ret setObject:oneCopy forKey:key];

        [oneCopy release];
    }

    return ret;
}
@end
person David Brainer    schedule 09.11.2011
comment
Мне это не понравилось... Теперь я получаю Incorrect decrement of the reference count of an object that is not owned at this point by the caller в этой новой строке... какие-нибудь дальнейшие идеи? - person Jules; 10.11.2011
comment
@Jules Я обновил свой ответ, чтобы отразить предоставленную вами дополнительную информацию. - person David Brainer; 11.11.2011
comment
@ Дэйв, я все еще получаю Incorrect decrement of the reference count of an object that is not owned at this point by the caller См. редактирование выше - person Jules; 11.11.2011
comment
@Jules Прошу прощения, возможно, я запутался, начав с упоминания метода автоматического выпуска. Поскольку в вашем случае вы (предположительно) хотите вернуть сохраненный объект, вторая часть моего ответа предполагает, что вы продолжаете сохранять объект и просто меняете имя своего метода. - person David Brainer; 11.11.2011

Здесь есть две проблемы. Во-первых, как говорит @David Brainer-Banker, вам нужно освобождать oneCopy в конце каждой итерации, помещая [oneCopy release]; after you set[ret setValue:oneCopy forKey:key];`.

Второй проблемой является неправильное уменьшение счетчика ссылок. Это связано с тем, что объект oneCopy может иметь счетчик ссылок +1 или 0. Объекты, возвращаемые -copy и -mutableCopy, имеют счетчик ссылок +1, но объект, возвращаемый -deepMutableCopy, имеет счетчик ссылок 0, поскольку он не входит в семейства new, copy или create (и др.).

Этот вопрос является точной копией этого и получил отличные отзывы.

person Alexsander Akers    schedule 10.11.2011