Мне показалось, что я понял базовый Objective-C в том, что касается методов alloc и init ..., но, похоже, я не понимаю. Я свел проблему, с которой столкнулся, к минимальному примеру ниже. (Для примера я помещаю все исходные тексты в один файл, но проблема возникает точно так же, если исходный код разбивается на несколько исходных файлов и заголовочных файлов, как обычно).
Вот краткий обзор того, что делает код и что происходит, когда я его запускаю.
Я определяю два класса MyInteger и MyFloat, которые почти идентичны, за исключением того, что один имеет дело с типом int, а другой с float. Оба имеют методы инициализатора, называемые initWithValue: однако с другим типом аргумента. Существует #define для контроля того, определен класс MyInteger или нет, причина в том, что он ведет к другому поведению программы, даже если этот класс никогда не используется.
Функция main () использует только MyFloat. Первые две строки делают это: выделяет экземпляр MyFloat и инициализирует его значением 50.0. Затем он печатает значение. В зависимости от того, определен MyInteger или нет, я получаю два разных выхода.
Без определения MyInteger, как я и ожидал:
[4138:903] float parameter value:50.000000
[4138:903] Value:50.000000
(next two output lines omitted)
С определением MyInteger, к моему большому удивлению:
[4192:903] float parameter value:0.000000
[4192:903] Value:0.000000
(next two output lines omitted)
Мне кажется, что компилятор обрабатывает вызов initWithValue: как будто он принадлежит классу MyInteger. Следующие две строки main () проверяют это путем приведения [MyFloat alloc] к типу MyFloat *. И это генерирует выходные данные, как ожидалось, даже когда MyInteger определен:
[4296:903] float parameter value:0.000000
[4296:903] Value:0.000000
[4296:903] float parameter value:50.000000
[4296:903] Value with cast:50.000000
Пожалуйста, объясните, что происходит! Я боролся с этим уже более 24 часов, вплоть до открытия дверей, чтобы немного нагреться, чтобы мой компьютер мог остыть :-) Спасибо!
Еще одна странность в том, что если я переместу определение MyInteger ниже определения MyFloat, то все будет «хорошо» - работает, как я и ожидал. История слишком часто доказывает, что я ошибаюсь, и я подозреваю, что виноват компилятор. В любом случае, вот информация о компиляторе и проекте: Использование Xcode 4.0.2. Пробовал со всеми 3 вариантами компилятора (GCC 4.2, LLVM GCC 4.2 и LLVM Compiler 2.0). Проект Xcode для этих примеров был настроен с использованием стандартной конфигурации для инструмента командной строки Mac OS X на основе Foundation.
#define DO_DEFINE_MYINTEGER 1
//------------- define MyInteger --------------
#if DO_DEFINE_MYINTEGER
@interface MyInteger : NSObject {
int _value;
}
-(id)initWithValue:(int)value;
@end
@implementation MyInteger
-(id)initWithValue:(int)value {
self= [super init];
if (self) {
_value= value;
}
return self;
}
@end
#endif
//------------- define MyFloat --------------
@interface MyFloat : NSObject {
float _value;
}
-(id)initWithValue:(float)value;
-(float)theValue;
@end
@implementation MyFloat
-(id)initWithValue:(float)value {
self= [super init];
if (self) {
NSLog(@"float parameter value:%f",value);
_value= value;
}
return self;
}
-(float)theValue {
return _value;
}
@end
//--------------- main ------------------------
int main (int argc, const char * argv[])
{
MyFloat *mf1= [[MyFloat alloc] initWithValue:50.0f];
NSLog(@"Value:%f",[mf1 theValue]);
MyFloat *mf2= [((MyFloat*)[MyFloat alloc]) initWithValue:50.0f];
NSLog(@"Value with cast:%f",[mf2 theValue]);
return 0;
}