2012-03-30 1 views
2

Я пытаюсь сделать прокси-сервер, который принимает любой селектор с любыми аргументами и посылает вызов RPC по проводу. В этом случае подпись метода неизвестна, поскольку он может быть произвольно создан конечным пользователем.Может ли методSignatureForSelector: создать сигнатуру метода «весь-весь»?

Я вижу, что для подписи метода требуется кодирование типа подачи для каждого из аргументов. Существует ли кодировка типа, которая означает абсолютно что-либо (указатель, int, все остальное)? Иначе, есть ли другой способ добиться этого эффекта?

ответ

2

«своего рода», но не совсем ... или, по крайней мере, не практически.

Вы можете реализовать протокол переадресации метода таким образом, чтобы нераспознанные вызовы методов были обернуты в NSInvocation, а затем вы могли разорвать NSInvocation, но это действительно нецелесообразно по ряду причин.

Во-первых, он действительно работает только для относительно простых типов аргументов. C ABI таков, что сложные аргументы - структуры, объекты C++ и т. Д. - могут быть закодированы в стеке по-разному. Фактически, они могут быть закодированы способами, когда метаданных недостаточно для декодирования кадров.

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

Кроме того, любая такая результирующая система будет исключительно хрупкой. Что, если «произвольный селектор», скажем, @selector (hash)?

2

Можете ли вы более подробно описать этот прокси-сервер и что ему нужно переслать?

Если ваш прокси-сервер должен перенаправить каждое сообщение на одну цель, он может сделать это в своем -forwardingTargetForSelector: во время выполнения. Если нет (например, вам нужно перенаправить несколько целей или выполнить другие сложные манипуляции), вам необходимо реализовать -forwardInvocation: для его обработки. Использование для обработки вызовов -forwardInvocation: требует, чтобы вы реализовали -messageSignatureForSelector:, потому что ему нужно получить подпись метода, чтобы иметь возможность создать вызов. (Даже если вы пересылаете его другому объекту, этот объект также должен либо реализовать метод напрямую, либо добавить метод в ответ на +resolveInstanceMethod:, либо обрабатывать его с помощью -forwardInvocation:, все из которых требуют, чтобы он также имел подпись.)

Подпись метода кодирует типы аргументов и тип возвращаемого значения. Причина, по которой эта информация необходима для вызова, заключается в том, что когда эти аргументы передаются, они выкладываются во время компиляции (возможно, последовательно) в памяти в соответствии с их типами в объявлении. Большой параметр struct будет занимать больше места, чем параметр int. Двойной также, вероятно, больше, чем int. Призыв должен хранить все эти аргументы и давать вам доступ или изменять их по индексу. Невозможно понять, как аргументы выставляются во время выполнения, если вы не знаете типы (или, по крайней мере, размеры типов).

Кроме того, механизм передачи сообщений отличаются для методов, которые возвращают структуры (они называют objc_msgSend_stret) от других методов (они называют objc_msgSend) (и на некоторых платформах, методы, которые возвращают двойники используют objc_msgSend_fpret). В первом случае структура не возвращается напрямую, но местоположение для записи в передается как дополнительный аргумент указателя в качестве параметра out. Поэтому знание типа возврата также имеет решающее значение для обработки вызова и возвращаемого значения в вызове.

Даже если вы перенаправляете вызов другому объекту, в конечном итоге этот объект (или какой-либо объект, который он отправляет вниз по линии) должен каким-то образом знать подпись метода. Так почему бы не спросить этот объект для подписи селектора, когда он вам нужен?

Нет «безопасной» подписи, которая будет работать на все, потому что разные типы имеют разные размеры.

Смежные вопросы