Переадресация вызовов методов на метод с другой сигнатурой в Objective-C? - PullRequest
1 голос
/ 19 февраля 2010

Я пытаюсь реализовать решение JSON-RPC, используя объект коннектора сервера, который получает список доступных функций с сервера, например,

NSDictionary *functions = [server  
    callJSONFunction: @"exposedFunctions" arguments: nil];

, что является упрощенным описанием, поскольку callJSONFunctionфактически запускает асинхронный NSURLConnection.

Элемент списка функций состоит из строки, описывающей селектор объекта c, исходное имя функции, которое будет вызываться с использованием механизма, упомянутого выше, сигнатура функции и необязательный массивимена аргументов.

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

( 
    @"someFunctionWithArgumentOne:argumentTwo:" =  
    {  
        signature = @"@@:@@",  
        functionName = @"someFunction",  
        arguments = ( @"arg_one", @"arg_two" )  
    },  
    @"anotherFunction" =  
    {  
        signature = @"@@:",  
        functionName = @"anotherFunction"  
    }  
)

Как только список функций был успешно получен, селекторы добавляются в экземпляр соединителя сервера с помощью class_addMethod в цикле:

for ( NSString *selectorName in functions ) {  
    SEL aSelector = NSSelectorFromString ( selName );  
    IMP methodIMP = class_getMethodImplementation ( 
        [ self class ], @selector ( callerMethod: ) );
    class_addMethod ( [ self class ], aSelector, methodIMP, "v@:@@@@" );
}

, где callerMethod: - это функция-обертка, используемая для составления фактического запроса, состоящая из имени функции в виде NSString и NSDictionary формы

{ @"argument1_name" = arg1, @"argument2_name" = arg2, ... }

отсюда и подпись "v @: @@".Затем callerMethod вызывает на сервере callJSONFunction.

После этого изнурительного вступления (мой плохой, я просто не знал, как его сократить), я наконец доберусь до сути: чтобы скрыть возможностьПо разному количеству аргументов я определил метод callerMethod как
- (void) callerMethod: (id)argument, ... { }
, в котором я использую макросы va_ * из stdarg.h для получения переданных аргументов.Но когда я проверяю механизм, вызывая

[serverConnector someFunctionWithArgumentOne: @"Argument 1"  
    argumentTwo: @"Argument 2" ];

, первый аргумент, возвращаемый id arg = va_arg ( list, id);, всегда @"Argument 2"!

Я действительно ценю все теории и объяснения того, почему это происходит,Эта штука действительно сводит меня с ума!

Ответы [ 2 ]

15 голосов
/ 19 февраля 2010

Var-args не отображаются на обычные аргументы, передаваемые так аккуратно. Кодирование аргументов на самом деле довольно специфично для архитектуры и изобилует очень интересными деталями, которые иногда кажутся противоречивыми (пока вы не обнаружите примечание об одном исключении из правила, которое делает все это согласованным). Если вы действительно хотите хорошее чтение [сарказм предназначен], посмотрите, как иногда ppc64 обрабатывает long double; бывают случаи, когда половина двойника будет в регистре, а другая половина в стеке. Whee!

Вышеупомянутый длинный и слегка пенистый из-за рубцов абзац говорит о том, что вы не можете прозрачно перенаправить вызов из одной функции в другую, где две функции принимают разные аргументы. Поскольку метод Objective C на самом деле является просто функцией, то же самое относится и к методам.

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

В вашем случае, однако, вы можете обойтись с помощью class_addMethod (), определив набор функций, которые определяют все возможные комбинации аргументации. Вам даже не нужно создавать словарь, так как вы можете использовать функцию dlsym() для поиска правильной функции. * 1012 Т.е. *

id trampolineForIdIdSELIdIdInt(id self, SEL _cmd, id obj1, id obj2, int) {
    ... your magic here ...
}

Затем вы можете перевести строку типа "@@: @@ i" в имя этой функции и передать ее в dlsym, получить результат и использовать class_addMethod() ....

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

1 голос
/ 20 февраля 2010

Также посмотрите эту незаконченную книгу Грегора Кикзалеса и Андреаса Пепке.

...