Есть ли ошибка в NSOperation в Mac OS X 10.6? - PullRequest
0 голосов
/ 04 октября 2009

Если я выпущу экземпляр NSOperation перед отправкой -init, я получу segmentation fault.

Причины, по-моему, это действительный код:

  • Apple делает это в своей документации .
  • Gnustep делает это в своем implementation of NSNumber, так что вполне вероятно, что это тоже в коде Apple. (По крайней мере, был.)
  • NSObject s -init ничего не делает, поэтому -release, который принадлежит NSObject, должен работать до этого.
// gcc -o test -L/System/Library/Frameworks -framework Foundation test.m

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    NSOperation *theOperation = [NSOperation alloc];
    [theOperation release];
}
  • Как вы думаете, это ошибка?
  • Можете ли вы показать мне пример другого класса с таким же поведением?
  • Есть идеи, почему это происходит?

Ответы [ 4 ]

7 голосов
/ 04 октября 2009

Отправка любого сообщения, кроме init, объекту, который не был инициализирован, не является допустимым кодом AFAIK. Вызовите инициализатор суперкласса, а затем отпустите, и я держу пари, что он не потерпит крах (хотя при возвращении инициализатора одного класса совершенно не связанный класс кажется мне doubleplusungood).

2 голосов
/ 04 октября 2009

Нет ничего удаленно действительного в этом коде.

Перепиши свой -init как:

- (id) init
{
    if (self = [super init]) {
        [self release];

        NSNumber *number = [[NSNumber alloc] initWithInteger:6];
        return number;
    }
    return self;
}

Конечно, код все еще бессмысленный, но он не падает.

Вы всегда должны звонить инициализатору суперкамера, прежде чем отправлять сообщения себе. И вы всегда должны делать это по схеме, показанной выше.

1 голос
/ 04 октября 2009

Мой предыдущий анализ был не совсем верным.

Однако я хочу отметить, что эта проблема может возникать с разными классами. Это на самом деле зависит от того, к какому классу вы относитесь. Создание подклассов NSObject не является проблемой, но, например, создание подклассов NSOperation, NSOperationQueue и NSThread.

И это происходит потому, что, как и ВЫ, классы, которые вы подклассируете, могут распределять вещи в своем методе -init. И это также, где вы устанавливаете nil переменные, которые вы еще не распределили (и могут сделать это позже в вашем коде).

Таким образом, вызывая -release для себя без предыдущего -init, вы можете заставить один из ваших родительских классов освободить объект, который он не выделил. И они не могут проверить, является ли их объект nil, потому что у него даже не было возможности инициировать каждый объект / значение, в котором он нуждается.

Это также может быть причиной того, что выпуск NSOperation без init работал на 10.5 и не работает на 10.6. Реализация 10.6 была переписана для использования блоков и Grand Central Dispatch, и поэтому их методы init и dealloc могли бы сильно измениться, что привело бы к другому поведению в этом фрагменте кода.

1 голос
/ 04 октября 2009

Я думал, что вам нужно инициализировать свой суперкласс перед вызовом release, но согласно этому примеру в документации Apple, это не так.

Так что это может быть ошибка, но определенно не важная.

...