Почему в Objective-C выполнение alloc и init в отдельных операторах приводит к освобождению объекта в соответствии со статическим анализатором Xcode? - PullRequest
4 голосов
/ 21 сентября 2011

Я делаю свои первые шаги в Objective-C и столкнулся с небольшой, хотя и запутанной проблемой со статическим анализатором (Product-> Analyze) в XCode 4.1.Я создал простой класс дроби для рациональных чисел, который я выделяю и инициализирую следующим образом:

Fraction* f = [[[ Fraction alloc ] initWithNumerator:3 withDenomimator:5]
                                                               autorelease];
[ f print ];

, где print - это метод, который просто использует NSLog для отображения дроби, все работает отлично.Однако, если я разделю конструкцию alloc / init на два утверждения (я понимаю, что это не идиоматично - я просто пытаюсь понять механизм) и использую руководство release вместо autorelease, дающее:

Fraction* f = [ Fraction alloc ]; // 1. Method returns an Objective-C object with
                                  //    a +1 retain count (owning reference)
[ f initWithNumerator:3 withDenomimator:5]; // 2. Object released
[ f print ]; // 3. Reference-counted object is used after it is released
[ f release ];

программа по-прежнему работает без ошибок, но анализатор XCode выдает предупреждения в комментариях.Почему XCode считает, что вызов init приводит к освобождению объекта?

Думая об этом, пока я формулирую вопрос, я вижу, что две мои программы не совсем эквивалентны, потому что в первом фрагменте мой указатель f - это результат вызова init, тогда как во втором фрагменте это результат alloc.Поэтому, изменив мой код на

 Fraction* a = [ Fraction alloc ];
 Fraction* f = [ a initWithNumerator:3 withDenomimator:5];
[ f print ];
[ f release ]; // or should it be [ a release ] ?

, он становится абсолютно эквивалентным, и статический анализатор перестает жаловаться.Так возможно ли, чтобы init мог возвращать другой указатель, чем тот, который был передан ему из alloc, а не просто , конфигурирующий память, которую он передал?С этим кодом я должен связать [ a release ] с alloc или [ f release ] с init?

Ответы [ 3 ]

5 голосов
/ 21 сентября 2011

Так возможно ли, чтобы init мог возвращать другой указатель, чем тот, который был передан ему из alloc, вместо того, чтобы просто сконфигурировать память, которую он передал?

абсолютно.

С этим кодом я должен связать [выпуск] с alloc или [f release] с init?

вы бы присвоили значение инициализированного объекта f (как у вас).в этот момент a может быть висящим указателем (если возвращается другой адрес).поэтому f должно быть release d.

. Объяснение этого порядка состоит в том, что объект, возможно, решил вернуть специализированную версию / вариант самого себя, и это перераспределение происходит по цепочке init....

глупая демонстрация:

@interface Fraction : NSObject
{
@private
    int numerator;
    int denominator;
}

@end

static Fraction* EvilFraction = ...;

@implementation Fraction

- (id)initWithNumerator:(int)num denominator:(int)den
{
    self = [super init];
    if (nil != self) {
        if (0 == den){
            [self release];
            return [EvilFraction retain];
        }
    }
    return self;
}

@end
2 голосов
/ 21 сентября 2011

Так возможно ли, что init может вернуть другой указатель, чем тот, который был передан ему из alloc, а не просто конфигурируя память, в которой он был передан?

Да, именно так. Это также причина, по которой вы не просто вызываете [super init] в инициализаторах; вместо этого вы вызываете его и присваиваете результат self, потому что вы не обязательно получите тот же экземпляр обратно.

Соответствующая документация находится на Языке программирования Objective-C .

С этим кодом я должен связать [ a release ] с alloc или [ f release ] с init?

Если вы действительно хотите сделать что-то подобное, вы должны сначала убедиться, что они не равны, иначе вы бы перевыпустили. Но реальное решение состоит в том, чтобы не разделять alloc и init. Это идиоматический способ создания объектов в Objective C, а другой способ добавления дополнительного кода - контрпродуктивен.

2 голосов
/ 21 сентября 2011

Apple пытается явно разделить вызовы на +alloc и -init, в соответствии с документацией для +[NSObject alloc]:

Для завершения должен использоваться метод init ...процесс инициализации.Например:

TheClass * newObject = [[TheClass alloc] init];

и -[NSObject init]:

В некоторых случаях initМетод может освободить новый объект и вернуть замену.Поэтому программы должны всегда использовать объект, возвращаемый init, а не обязательно тот, который возвращается alloc или allocWithZone:, в последующем коде.

Статический анализатор жалуется, поскольку ожидает, что +alloc будетв паре с -init.Поскольку -init может освободить отправителя, статический анализатор считает, что вы пытаетесь вызвать метод для освобожденного экземпляра.

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