Вызов метода для неинициализированного объекта (нулевой указатель)
- Что такое нормальное поведение в Objective-C, если вы вызываете метод на объекте (указатель), который равен нулю (возможно, потому что кто-то забыл инициализировать его)? Должна ли она генерировать какую-то ошибку (ошибка сегментации, исключение нулевого указателя...)?
- Если это нормальное поведение, есть ли способ изменить это поведение (путем настройки компилятора), чтобы программа вызывала какую-либо ошибку/исключение во время выполнения?
Чтобы было более ясно, о чем я говорю, вот пример.
Наличие этого класса:
@interface Person : NSObject {
NSString *name;
}
@property (nonatomic, retain) NSString *name;
- (void)sayHi;
@end
с этой реализацией:
@implementation Person
@synthesize name;
- (void)dealloc {
[name release];
[super dealloc];
}
- (void)sayHi {
NSLog(@"Hello");
NSLog(@"My name is %@.", name);
}
@end
Где-то в программе я делаю это:
Person *person = nil;
//person = [[Person alloc] init]; // let say I comment this line
person.name = @"Mike"; // shouldn't I get an error here?
[person sayHi]; // and here
[person release]; // and here
Ответы
Ответ 1
Сообщение, отправленное nil
объекту, совершенно приемлемо в Objective-C, оно рассматривается как запрет. Нет способа пометить его как ошибку, потому что это не ошибка, на самом деле это может быть очень полезной функцией языка.
Из документов:
Отправка сообщений на ноль
В Objective-C допустимо отправлять сообщение на ноль - оно просто не имеет никакого эффекта во время выполнения. Есть несколько моделей в Cocoa, которые используют в своих интересах этот факт. Значение, возвращаемое из сообщения в nil, также может быть допустимым:
-
Если метод возвращает объект, то сообщение, отправленное на nil
возвращает 0
(nil
), например:
Person *motherInLaw = [[aPerson spouse] mother];
Если spouse
aPerson
равен nil
, mother
отправляется на nil
а метод возвращает nil
.
-
Если метод возвращает любой тип указателя, любой целочисленный скаляр с размером, меньшим или равным sizeof(void*)
, с float
, double
, long double
или long long
, то сообщение, отправленное на nil
возвращает 0
.
-
Если метод возвращает struct
, как определено в Руководстве по вызову функции ABI для Mac OS X, для возврата в регистры, то сообщение, отправленное на nil
возвращает 0.0
для каждого поля в структуре данных. Другие типы данных struct
не будут заполнены нулями.
-
Если метод возвращает что-либо кроме вышеупомянутых типов значений, возвращаемое значение сообщения, отправленного на ноль, не определено.
Ответ 2
Из Грег Паркер сайт:
Если выполняется LLVM Compiler 3.0 (Xcode 4.2) или более поздняя версия
Messages to nil with return type | return
Integers up to 64 bits | 0
Floating-point up to long double | 0.0
Pointers | nil
Structs | {0}
Any _Complex type | {0, 0}
Ответ 3
Одна вещь, о которой вам следует знать, заключается в том, что в Objective-C вы не вызываете метод на объект, вы отправляете сообщение объекту. Время выполнения найдет метод и вызовет его.
Начиная с первых версий Objective-C, сообщение nil всегда было безопасным no-op, которое возвращает nil. Там много кода, который зависит от этого поведения.