objc_msgОтправить макрос на arm64

Я пытаюсь понять разницу между id objc_msgSend(id self, SEL op, ...) и void objc_msgSend(void)

У меня есть этот макрос, который работал для методов всех типов. Однако при переходе на arm64 эта версия objc_msgSend больше недоступна.

#define safePerformSelector(target, selector, ...) ([target respondsToSelector:selector] ? objc_msgSend(target, selector, ##__VA_ARGS__) : nil)

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

#define safePerformSelector(target, selector, ...) ([target respondsToSelector:selector] ? ((id (*)(id, SEL, ...))objc_msgSend)(target, selector, ##__VA_ARGS__) : nil)

person CrimsonChris    schedule 02.06.2014    source источник


Ответы (1)


Вы всегда должны сначала привести objc_msgSend() к правильному типу указателя функции. Тип id(*)(id, SEL, ...) не является правильным типом, если только ваш метод действительно не возвращает id и не принимает ... (что IIRC синтаксически невозможно).

Если вы вызываете objc_msgSend() с неверным типом функции, то вызываемый метод может неправильно получать значения параметров.

person Greg Parker    schedule 02.06.2014
comment
Мне не нужно было ничего приводить, используя мой исходный макрос. Он отлично работал для всех видов методов. - person CrimsonChris; 03.06.2014
comment
Для некоторых сигнатур методов и некоторых архитектур это не удастся. В частности, он почти всегда будет работать неправильно на arm64. - person Greg Parker; 03.06.2014
comment
Эта проблема возникла при переходе на arm64. Я полагаю, вы хотите сказать, что я больше не смогу этого делать? По крайней мере, не так чисто. - person CrimsonChris; 03.06.2014
comment
Можно ли сделать это с помощью одного макроса на всех архитектурах? - person CrimsonChris; 03.06.2014
comment
Невозможно использовать один макрос, действительный для всех сигнатур методов на всех архитектурах. - person Greg Parker; 03.06.2014
comment
Даже не используя другой подход? NSInvocation выглядит многообещающе. - person CrimsonChris; 03.06.2014
comment
Поверьте, что @GregParker знает, о чем говорит! - person sbooth; 07.06.2014
comment
Почему бы не использовать #ifdef для каждой архитектуры? - person nielsbot; 07.06.2014
comment
Вы можете использовать разные определения для каждой архитектуры и каждой сигнатуры метода. Вы не можете безопасно обрабатывать сигнатуры произвольных методов даже на одной архитектуре. - person Greg Parker; 07.06.2014
comment
Почему это так просто и прямолинейно на x86, но невозможно на arm64? Я не понимаю, почему изменение архитектуры может вызвать это. - person CrimsonChris; 07.06.2014
comment
На x86_64 не просто. Ваш макрос неверен и для некоторых сигнатур методов. arm64 усугубляет ситуацию, потому что в его ABI больше мест, где вызов vararg отличается от вызова без vararg. - person Greg Parker; 07.06.2014
comment
@GregParker Для каких сигнатур методов это неверно на x86_64? - person CrimsonChris; 10.06.2014
comment
Любой метод, который имеет параметр типа float, для начала. - person Greg Parker; 21.06.2014