2009-10-04 4 views
0

Если я отпустил экземпляр NSOperation перед отправкой -init к нему, я получаю segmentation fault.Есть ли ошибка в NSOperation в Mac OS X 10.6?

Причины я думаю, что это правильный код:

  • Apple, делает это в its documentation.
  • 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]; 
} 
  • Как вы думаете, это ошибка?
  • Можете ли вы показать мне пример другого класса, который имеет такое же поведение?
  • Любая идея, почему это происходит?
+0

@gs Пожалуйста, прочитайте мой комментарий, отвечая на ваш ответ :) –

+0

Моя точка еще стоит :). Я уверен, что '-init' NSOperation выделяет некоторый указатель (на структуру или что-то еще). Значение указателя не задано 'NULL' временем выполнения, поэтому вызов' -release' освобождает указатель, который не был инициирован, и чье значение my равно 0 (иначе у вас нет доступа: D) –

ответ

7

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

+1

Правильный ответ , Больше деталей в виду. Я фактически скомпилировал тестовый проект, чтобы убедиться, что это где-то не было скрытой ошибкой. Это не так. – bbum

+0

Возвращение совершенно несвязанного класса только для примера. Я не делаю этого в своем рабочем коде. Класс Gnustep 'NSNumber' также отправляет' -release' перед инициализацией. '-initWithCoder' никогда не вызывает' -init', насколько мне известно. –

+0

'initWithCoder:' методы обычно переходят в супер. – Chuck

2

В этом коде нет ничего отдаленного.

Перепишите ваш -init как:

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

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

Конечно, код все еще ерунда, но это не катастрофа.

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

+1

Я изменил код, чтобы избежать более подробного обсуждения кода. Освобождение до инициализации действительно: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html#//apple%5Fref/doc/uid/TP30001163-CH22-SW13 –

1

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

Это может быть ошибка, но, конечно, не важная.

+1

Я думаю, вы нашли ошибку в документации. – Chuck

1

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

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

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

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

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

+0

Отправка '-release' никому не должна ничего делать. Кроме того, освобождение указателей «NULL» должно ничего не делать. http://www.opengroup.org/onlinepubs/009695399/functions/free.html Поэтому я считаю, что это ошибка. –

+0

@gs: Iknow free() и отпустите работу над объектами NULL. Однако, когда вы хотите, чтобы они указали указатель на NULL/nil, когда вы даже не позволили им запустить свой объект? (это моя точка в этом ответе). Выделение указателя в стеке не устанавливает его в NULL/nil. Вот почему я думаю, что это НЕ ошибка. –

+1

Ivars автоматически устанавливаются на nil в alloc. – Chuck