Изпълнете предупреждение за селектор срещу изпращане _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 благодаря, знам.. използвайте директно функцията за изпълнение, мога да избегна предупреждението, но (имам предвид ;-) ) възможно ли е да няма друго friednly решение?   -  person Andrea    schedule 03.06.2013
comment
@Andrea: Струва ми се, че имате 2 различни проблема: 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