Objective-C va_list и селекторы - PullRequest
       4

Objective-C va_list и селекторы

2 голосов
/ 26 января 2010

Можно ли использовать @selector и performSelector: (или аналогичные) с методами, использующими список переменных аргументов?

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

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

- (void)logEventWithFormat:(NSString *)format, ... {
    va_list argList;
    id del = self.delegate;
    if (del != nil && 
        [del conformsToProtocol:@protocol(AProtocolWithOptionalMethods)] &&
        [del respondsToSelector:@selector(logEventWithFormat:)])
    {
        // Perform selector on object 'del' with 'argList'
    }
}

Я предполагаю, что это невозможно, поэтому аналогичное объявление метода в структуре Foundation - в NSString:

- (id)initWithFormat:(NSString*)format, ...;

и

- (id)initWithFormat:(NSString *)format arguments:(va_list)argList;

Я предполагаю, что протокол, которому я хочу делегировать, должен предлагать реализацию:

- (void)logEventWithFormat:(NSString *)format arguments:(va_list)argList;

так что селектор @selector(logEventWithFormat:arguments:) может использоваться вызываемым с:

[del performSelector:@selector(logEventWithFormat:arguments:) 
          withObject:format
          withObject:argList];

Я просто подумал, что я что-то упустил или проделал долгий путь, чтобы достичь того, что я пытаюсь сделать?

Ответы [ 4 ]

4 голосов
/ 26 января 2010

Вы можете передать все, что захотите, в функцию времени выполнения objc_msgSend.

objc_msgSend(del, @selector(logEventWithFormat:arguments:), format, argList);

Это самый мощный способ отправки сообщения, созданного вручную.

Однако, не ясно, что вам нужно выполнить вызов таким способом. Как указал KennyTM, в имеющемся коде вы можете вызывать метод напрямую.

2 голосов
/ 26 января 2010

Вы не можете использовать -performSelector:withObject:withObject:, потому что va_list просто не является "объектом". Вам нужно использовать NSInvocation.

Или просто позвоните

[del logEventWithFormat:format arguments:argList];
2 голосов
/ 26 января 2010

Насколько я знаю, это невозможно сделать. Вы не можете использовать -performSelector:withObject:withObject:, потому что, как указывает @KennyTM, va_list не является объектом.

Однако вы также не можете использовать NSInvocation. Документация прямо гласит:

NSInvocation не поддерживает вызовы методов либо переменные числа аргументов или объединения аргументы.

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

Возможно, @bbum появится и просветит нас. =)

0 голосов
/ 26 января 2010

Раньше я так не делал, но простое решение, которое я часто использовал, - это блокировать / распаковывать NSMutableArray или NSMutableDictionary для параметра withObject.

...