Выполнить предупреждение селектора против отправки _async

[НЕ ДУБЛИРУЙТЕ: внимательно прочитайте вопрос и уже данные ответы, я их уже читал]

Я столкнулся с этой проблемой, мне нужно заменить метод -performSelector, так как он вызывает это предупреждение в компиляторе с ARC

PerformSelector может вызвать утечку, потому что его селектор неизвестен.

Я знаю, что есть разные вопросы по этой теме:

и я также знаю о методах, позволяющих избежать этого предупреждения.
Иногда в качестве решения я обнаруживал, что наиболее рекомендуемым советом является использование dispatch_async(dispatch_get_main_queue(),^(void) { WHATEVER });, но, насколько я знаю, диспетчеризация потребует выполнения блока при следующем запуске. цикл, -performSelector (без задержки) выполняется сразу.
К чему эта мысленная мастурбация? Представьте, что вы используете новый метод Gamekit для аутентификации, игровой комплект может отправить вам внутри блока аутентификации контроллер представления, чтобы заставить пользователя выполнить какую-либо операцию (например, создать идентификатор, войти в систему и т. д.). Было бы полезно предупредить пользователя, если он/она хочет увидеть этот контроллер представления. Для этого и прочего я пишу протокол. В частности, этот метод должен возвращать BOOL - (BOOL)shouldLoadGameKitViewController: (UIViewController*) viewController;, я бы хотел вызвать его, используя -performSelector. В том-то и дело, что если метод не вернётся сразу, я не смогу получить ответ от делегата.
Я использую NSInvocation, чтобы это произошло, но он многословен, существует ли какой-то другой способ?

[ОБНОВЛЕНИЕ С КОДОМ]
Обратите внимание, что теперь, когда я использую вызов, часть проверки потока еще не реализована. В комментарии есть та часть, которая выдала предупреждение

- (void) dispatchToDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
    NSMethodSignature *methodSig = [[self class] instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
    [invocation setTarget:self.delegate];
    if([self.delegate respondsToSelector: selector])
    {
        if(arg != NULL) {
            [invocation setArgument:&arg atIndex:2];      
            [invocation setArgument:&err atIndex:3];      

//          [_delegate performSelector: selector withObject: arg withObject: err];

        }else {
            [invocation setArgument:&err atIndex:2];      
//            [_delegate performSelector: selector withObject: err];

        }
        [invocation invoke];

    }
    else
        DLog(@"Method not implemented in the delegate");
}

[ВИД РЕШЕНИЯ ЕЩЕ НЕ ПРОВЕРЕНО]

- (BOOL) dispatchToDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
    NSMethodSignature *methodSig = [[self class] instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
    [invocation setTarget:self.delegate];
    BOOL result = NO;
    if([self.delegate respondsToSelector: selector])
    {
        if(arg != NULL) {
            [invocation setArgument:&arg atIndex:2];      
            [invocation setArgument:&err atIndex:3];      

//          [_delegate performSelector: selector withObject: arg withObject: err];

        }else {
            [invocation setArgument:&err atIndex:2];      
//            [_delegate performSelector: selector withObject: err];

        }
        if ([NSThread isMainThread]) {
            [invocation invoke];        
        }
        else{
            [invocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:YES];
        }
        [invocation getReturnValue:&result];
    }
    else
        NSLog(@"Missed Method");
    return result;
}

Используя метод NSMethodSignature, можно настроиться и запросить тип возвращаемого значения. Я все еще не тестировал, но это должно было помочь.


person Andrea    schedule 03.06.2013    source источник
comment
Зачем вообще нужен performSelector? Если у вас есть делегат, соответствующий протоколу, вы можете вызвать метод напрямую: BOOL b = [self.delegate shouldLoadGameKitViewController:...].   -  person Martin R    schedule 03.06.2013
comment
Потому что у меня есть метод, который перед вызовом запрашивает основной поток, так как вы не знаете, где будет вызываться блок.   -  person Andrea    schedule 03.06.2013
comment
Итак, вы заменяете performSelectorOnMainThread? Возможно, вы можете показать соответствующий код, тогда легче помочь.   -  person Martin R    schedule 03.06.2013
comment
В сообщении о переполнении стека примера 2 посмотрите ответ, который подавляет предупреждение для этой строки кода. Используйте это.   -  person bandejapaisa    schedule 03.06.2013
comment
возможный дубликат performSelector может вызвать утечку, поскольку его селектор неизвестно   -  person jrturton    schedule 03.06.2013
comment
@jrturton Это не дубликат, внимательно прочитайте вопрос, я не ищу общего решения, чтобы избежать предупреждений. Я уже прочитал все остальные вопросы.   -  person Andrea    schedule 03.06.2013
comment
@bandejapaisa спасибо, я знаю .. используйте непосредственно функцию времени выполнения, я могу избежать предупреждения, но (я имею в виду ;-)) возможно ли, что нет другого удобного решения?   -  person Andrea    schedule 03.06.2013
comment
@Andrea: Мне кажется, у вас две разные проблемы: 1) Избегайте предупреждения PerformSelector. Это можно решить, например. с NSInvocation. - 2) Проблема с потоками. Чтобы выполнить метод в основном потоке, вы должны вызвать performSelectorOnMainThread или dispatch_(a)sync. В обоих случаях метод не может вернуть значение вызывающему потоку, если вы не дождетесь завершения, но это может легко привести к взаимоблокировке.   -  person Martin R    schedule 03.06.2013
comment
@MartinR Спасибо .. да, наверное, я нашел решение, завтра выложу результаты   -  person Andrea    schedule 03.06.2013


Ответы (2)


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

SEL selector = NSSelectorFromString(@"methodName::");
if ([obj respondsToSelector:selector])
    [obj performSelector:selector withObject@[args,array]];
person user1468634    schedule 03.06.2013
comment
Это не заставляет исчезнуть исчезновение - person Andrea; 03.06.2013

Вы можете использовать dispatch_sync вместо dispatch_async для немедленного выполнения блока (ваш код будет заблокирован до тех пор, пока блок не вернется).

Другой альтернативой является временное подавление предупреждения, как описано в этом ответе.

person Gerd K    schedule 03.06.2013
comment
Таким образом, вы вызовете взаимоблокировку отправлять в основную очередь синхронно без взаимоблокировки"> stackoverflow.com/questions/10330679/ - person Andrea; 03.06.2013
comment
dispatch_async может быть выполнено немедленно. Единственная разница между async и sync заключается в том, что блок гарантированно полностью выполнится до возврата последнего. - person bbum; 03.06.2013