Не могу разобраться в этой динамической типизации

#objective-c #cocoa #dynamic-typing

#objective-c #какао #динамическая типизация

Вопрос:

Я составляю список вопросов для собеседования для кого-то, кто хочет стать разработчиком Cocoa. Я программист, но я никогда не делал Objective-C. Я наткнулся на интересный вопрос, который включает динамическую типизацию. Это должно быть элементарно, я попробовал и скомпилировал его, но я все еще не уверен, как и почему это работает.

Вопрос в том

Что происходит во время компиляции и во время выполнения, когда вы выполняете следующее:

 NSString *s = [NSNumber numberWithInt:3];
int i = [s intValue];
  

В отладчике я получаю

i = (int) 3
s = (__NSFCNumber *) 0x383 (недопустимый адрес)

Вывод NSLog(@"%d",i) есть 3 , а вывод NSLog(@"%@",s) есть 3 .

Может кто-нибудь дать мне объяснение того, как все это обрабатывается компилятором и системой выполнения, также пытаясь иметь в виду, что я совершенно новичок в Objective-C и Cocoa, но совсем не новичок в информатике?

Ответ №1:

Ваш s — это просто стандартный указатель C, которому присваивается NSNumber объект (указатель на a).

NSNumber , а также NSString , отвечает на intValue . Вот и все.

Комментарии:

1. Дополнительный комментарий по поводу интервью: любой хороший программист может выучить любой язык, поэтому меня больше интересует понимание возможностей интервьюируемых, чем их знаний. Вопросы тестового типа, которые я ненавижу, хотя те, что указаны в вашей ссылке, в основном являются хорошим началом для разговора.

2. Ваше последнее предложение — это то, чего мне не хватало. Я не понимал, что оба типа отвечают intValue .

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

Ответ №2:

s указатель, который вы объявили, будет указывать на NSString объект. Он может указывать на что угодно, но в идеале он должен указывать на NSString . Однако пример кода s указывает на объект NSNumber .

Пока вы отправляете только методы s , которые являются методами, которые NSNumber реагируют на все нормально (за исключением, может быть, предупреждений компилятора). Если бы вы попытались отправить метод NSString этому объекту, на который указывает, s что NSNumber не отвечает, вы бы получили исключение. Если объект имеет соответствующую сигнатуру селектора (т. Е.: @selector(intValue) ), Будет вызван метод.

Комментарии:

1. Не совсем правильно, поскольку intValue на самом деле является методом в NSString. Возможно, лучше сказать, что и NSNumber, и NSString реагируют на сигнатуру (или значение @selector) intValue .

Ответ №3:

Объявление NSString для переменной «s» выполняется просто для того, чтобы помочь компилятору интерпретировать ваше намерение переменной «s». Это позволяет компилятору принудительно выполнять статическую проверку типов в случае, когда вы намеревались использовать переменную определенного типа, но случайно назначили переменную другого типа. В ObjC переменная может указывать на любой объект, в то время как синтаксис скобок является средством отправки «сообщения» объекту. Отправка сообщения предписывает компилятору сгенерировать код, который ищет функцию, реализующую сообщение. Также в ObjectiveC сообщения называются селекторами. (Детали низкого уровня немного сложнее, но на высоком уровне так оно и работает.) Это динамическая часть dynamic typic, которую также называют «утиной типизацией». Идея в том, что если он выглядит как утка, вы должны быть в состоянии заставить его крякать, как утка. По сути, любому объекту, который соответствует определенной форме, может быть присвоен тип, соответствующий форме.

Рассмотрим следующее:

 Dog *myPuppy = [[Cat alloc] init] autorelease];
[myPuppy walk];
Food *preparedDish = [self prepareMealForPet];
[myPuppy eat: preparedDish];
  

Компилятор пометит вас здесь, указав, что вы намеревались провести время с собакой, но на самом деле имеете дело с кошкой. Однако это совершенно справедливо, поскольку кошка имеет форму, похожую на собаку, в том смысле, что они оба могут ходить и есть готовые блюда. Утиный ввод позволяет вам избежать этого, поскольку во многих случаях вам нужно будет принимать типы переменных, которые заранее неизвестны. Кроме того, с помощью самоанализа вы можете обнаружить форму вашего объекта во время выполнения. Рассмотрим в приведенном выше коде, хотим ли мы попросить нашего щенка лаять. Мы получим исключение, и приложение завершит работу. Однако мы могли бы использовать самоанализ, чтобы спросить, отвечает ли наш объект на сообщение «bark», чтобы избежать сбоя.

 if([myPuppy respondsToSelector:@selector(bark)]) {
   [myPuppy bark];
}