Есть ли способ обеспечить проверку типов во время выполнения в Objective-C на Cocoa?

Привет, я нахожу способ обеспечить проверку типов во время выполнения или подобные вещи в Objective-C на Cocoa.

Это мой пример кода. Я ожидал ошибки времени выполнения из-за неправильного назначения переменной «b». Но это не так. Скомпилировалось и запустилось без ошибок.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 NSArray* a = [NSArray arrayWithObject: @"TEST"]; 
 NSURL* b = [a objectAtIndex:0]; 

    NSLog(@"Is this URL? %i", [b isKindOfClass:NSURL.class]);
    [pool drain];
    return 0;
}

// Console log after program execution:
// 2010-01-11 10:25:02.948 Type Checking[98473:a0f] Is this URL? 0

Я удивлен тем, что там нет проверки типа во время выполнения. Поскольку я использовал все языки высокого уровня, такие как VB, C#, Java, ActionScript... Я не знаю языка низкого уровня, такого как C, поэтому я не уверен, что это правильный путь... Было очень сложно понять почему нет ошибки компиляции или времени выполнения. Но я начинаю понимать это как естественное правило в реальном мире C. Но мне очень поможет более строгая проверка типов. Даже только в сеансе отладки. Есть какой-либо способ сделать это?

И если нет проверки типа во время выполнения, какую стратегию кодирования и отладки я должен использовать для неправильных типизированных значений? И какой компромисс между проверкой типа во время выполнения или нет?


person Community    schedule 11.01.2010    source источник
comment
Я не вижу никаких причин для того, чтобы этот пост был вики-сообществом   -  person calvinlough    schedule 11.01.2010
comment
Извините, я плохо разбираюсь в правилах здесь. Есть ли какое-либо наказание за использование «вики-сообщества»?   -  person eonil    schedule 11.01.2010


Ответы (3)


В Objective-C есть проверка типов во время компиляции для аргументов сообщений и возвращаемых типов, но она несколько слабее, чем многие другие языки. Одним из основных отличий является то, что классы коллекций, такие как NSArray и NSDictiomary, являются универсальными. Вы можете поместить объект любого типа в NSArray — элементы не обязательно должны быть одного типа. Таким образом, при добавлении элементов или доступе к ним не выполняется проверка типов.

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

person Community    schedule 11.01.2010
comment
Спасибо за ответ. Я также понял этот факт с ошибкой, вызванной неизвестным сообщением. Я позабочусь о нем еще больше. - person eonil; 11.01.2010

Ну, есть проверка типов во время выполнения, но это происходит чуть позже. Я предполагаю, что вы ожидаете какое-то исключение, когда пытаетесь поместить экземпляр NSString в переменную NSURL*. Вместо этого вы получите исключение, когда попытаетесь вызвать любые методы, специфичные для NSURL, в вашем экземпляре NSString.

Например, если вы попробуете [b isFileURL], вы получите исключение вроде «NSString не отвечает на селектор isFileURL».

Также важно понять, почему в вашем примере нет проверки типов во время компиляции. В частности, отсутствие проверки типа во время компиляции является уникальным и важным свойством типа id, которое возвращает -objectAtIndex: NSArray.

person Community    schedule 11.01.2010
comment
Я понимаю. Не исключение при назначении. А компилятор проверяет только строго типизированные переменные. Не для типов идентификаторов. Спасибо за ответ. - person eonil; 11.01.2010

NSObject Framework часто поднимает шум, когда тип неправильный, но вы можете вручную проверить тип и выдать исключение:

if (![obj isKindOfClass:SomeObjectClass.class])
  [NSException raise:@"BadTypeException"
    format:@"Bad type at line %d", (int)__LINE__];
[obj xyz];

...

if (![obj conformsToProtocol:@protocol(SomeProtocol)])
  [NSException raise:@"BadTypeException"
    format:@"Bad type at line %d", (int)__LINE__];
[obj abc];

Изменить: удален предыдущий раздел, в котором утверждалось, что вызовы несуществующих методов возвращают nil или нули; как говорит Марк Бесси, возникает исключение (возвращается не ноль), если ненулевой объект не реализует метод.

person Community    schedule 11.01.2010
comment
Если вы вызываете нереализованный метод, он вызывает исключение. Вы думали об отправке сообщений на нулевую ссылку на объект? Это возвращает ноль. - person Mark Bessey; 11.01.2010
comment
Спасибо, Марк. Я сделал исправление, чтобы отразить это - person martinr; 11.01.2010
comment
Точное поведение отправки сообщения, на которое получатель не отвечает, определяется методом forwardInvocation:. По умолчанию этот метод вызывает doesNotRecogniseSelector: для self, а doesNotRecogniseSelector: по умолчанию вызывает исключение, однако это поведение может быть переопределено подклассами и, следовательно, не всегда вызывает исключение. - person dreamlax; 11.01.2010
comment
Я принял «ноль возвращает ноль, а другие выдают исключение» как в основном. Я буду помнить это. Спасибо всем! - person eonil; 11.01.2010