Вызывать функцию Objective C не виртуально - PullRequest
0 голосов
/ 22 сентября 2011

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

Например, учитывая классы A и B, которые реализуют - (void) foo, где B - это подкласс A, я хотел бы вызвать метод foo для A с экземпляром B (даже если B обычно обрабатывает это сообщение).

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

ПРИМЕЧАНИЕ. Для целей этого вопроса предположим, что я не могу изменить источник A или B, и я тщательно взвесил риски нарушения инкапсуляции.

Ответы [ 2 ]

4 голосов
/ 22 сентября 2011

Эта страница является отличным источником для понимания времени выполнения; быстрое сканирование с помощью памяти показывает, что раздел «Так что же происходит в objc_msgSend?» это хорошее место для немедленного ответа, но статья в целом действительно поможет вам понять, что происходит.

Вот пример, где он запрашивает во время выполнения соответствующий указатель на функцию, а затем напрямую вызывает функцию:

//declare C function pointer
int (computeNum *)(id,SEL,int);

//methodForSelector is COCOA & not ObjC Runtime
//gets the same function pointer objc_msgSend gets
computeNum = (int (*)(id,SEL,int))[target methodForSelector:@selector(doComputeWithNum:)];

//execute the C function pointer returned by the runtime
computeNum(obj,@selector(doComputeWithNum:),aNum); 
3 голосов
/ 23 сентября 2011

То, что сказал Матиас ... однако:

Например, для заданных классов A и B, которые реализуют - (void) foo, где B - это подкласс A, я хотел бы вызватьметод foo на A с экземпляром B (хотя B обычно обрабатывает это сообщение).

Другими словами, у вас есть реализация foo на B, которую вы хотите избежать, вызываяРеализация a напрямую?

Очевидно, что если вы реализатор B, то это тривиально;просто реализуйте соответствующую логику, чтобы определить, когда это необходимо, и вызовите [super foo];.

. Если вы не реализатор B, то это за пределами плохой идеи.Это в значительной степени может привести к загадочным сбоям и / или неправильному поведению.Хуже того, если B на самом деле является частью системной структуры или чего-то, что может обновляться с помощью механизма, отличного от обновляемого вашего приложения, то у вас есть бомба замедленного действия, которая может в любой момент начать сбой вашего приложения на любой случайной конфигурацииOS.

В частности:

  • B foo не может быть автономным;он может делать что-то до / после вызова A foo, который устанавливает внутреннее состояние, которое впоследствии может потребоваться для продолжения правильной работы.Вы нарушаете инкапсуляцию кувалдой.

  • , вызывая реализацию напрямую, обходит любое КВО в игре.Если вам не удастся захватить реализацию производного метода, в этот момент ваше поведение взорвется, когда этот производный метод больше не будет в игре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...