Подтвердить что ты не робот

Вызов метода для неинициализированного объекта (нулевой указатель)

  • Что такое нормальное поведение в 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
4b9b3361

Ответ 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. Там много кода, который зависит от этого поведения.