2010-10-26 4 views
1

Проведя отлаженные от этого времени годы, я очень хочу понять, что именно происходит!Объективные копии сигнатуры метода C

В очень надуманный пример, скажем, у нас есть два объекта, Object1 имеет этот метод:

- (void) testMethod:(NSString *)testString 

Объект 2 имеет этот метод:

- (void) testMethod:(NSArray *)testArray 

Затем обратно в Object1, в методе есть следующий код:

NSArray *myArray = [[NSArray alloc] init];  
[[[Object2 alloc] init] testMethod:myArray]; 

Whe п я компилирую, Xcode дает предупреждение:

Несовместимые типы указателей отправки «NSArray *» для параметра типа «NSString *»

Я считаю, что я прав, говоря, предупреждение происходит потому, что я никогда не указывать тип объекта Object2. Явное литье объекта Object2 фиксирует это, но мои вопросы таким образом:

  1. При вызове TestMethod на Object2, почему это с помощью метода из Object1, когда объектов нет ничего общего друг с другом?
  2. Почему предупреждение исчезает, если я перемещаю #import "Object2.h" в Object1.h вместо Object1.m?

Спасибо!

ответ

6

Когда есть два метода с одним и тем же селектором, но с разными сигнатурами, компилятор должен решить, какую подпись использовать во время компиляции, потому что подпись может повлиять на генерируемый код. К сожалению, компилятор очень глуп, и единственный способ определить, какая подпись использовать, проверит статический тип получателя. В этом случае оба alloc и возвращают id, поэтому компилятор имеет никакой информации, с помощью которой он может решить, к какому объекту вы отправляете это сообщение. Таким образом, это в основном делает это, чтобы сломать галстук: он закрывает глаза, крутится вокруг по кругу несколько раз, и какая бы подпись не указывала, когда она останавливается, это тот, который он использует. Затем он проверяет ваш тип аргумента на эту стохастическую подпись, и если он догадался, что он ошибался, он считает, что вы передали неправильный тип.

Лучшее решение - избежать столкновений с сигнатурой - имена описательного метода обычно сами по себе заботятся об этом, и добавление большей специфичности для одного или обоих селекторов часто является хорошим способом решения проблемы, с которой вы сталкиваетесь (например, make это testMethodWithName:(NSString *)name).

Это также хорошая идея статически вводить вещи, насколько это возможно. Обычно это не проблема, потому что вы все равно хотите назначить вновь созданный объект переменной. В крайнем случае, когда было бы просто неудобно назначать результат метода переменной, вы также можете просто отнести неоднозначную часть к правильному типу, например [(Object2 *)[[Object2 alloc] init] testMethod:myArray].

+0

+1 особенно для описательного метода name advice – JeremyP

+0

Спасибо, ваше вращение по кругу аналогично, в основном говоря, что поведение Objective C просто неопределено, когда нет явного типа приведения? Это объясняет, почему перемещение #import изменило поведение. –

+0

@Tom Gilder: Да. Это не неопределенное поведение в традиционном смысле C, но оно также не определяется каким-либо полезным способом. Вот почему перемещение импорта будет иметь значение, хотя нет очевидной причины, почему это произойдет. – Chuck