1

[NOT DUPLICATE: read well the question and the already given answers, I've already read them]

I'm facing that problem, I need to substitute -performSelector method since it causes that warning in the compiler with ARC

performSelector may cause a leak because its selector is unknown

I'm aware that there different questions about that topic:

and I'm also aware about the techniques to avoid that warning.
Sometimes as a solution I found that the most suggested advice is to use dispatch_async(dispatch_get_main_queue(),^(void) { WHATEVER }); but as far as I know dispatching would require the execution of the block in the next run loop, -performSelector (without delay) is executed immediately.
Why this mental masturbation? Imagine that you are using the new Gamekit method for authentication, game kit could send you inside the auth block a view controller to make the user do some operation (such as creating the id, log in, etc). It could be useful to warn the user if he/She wants to see that view controller. To do that and other stuffs I'm writing a protocol. In particular that method should return a BOOL - (BOOL)shouldLoadGameKitViewController: (UIViewController*) viewController;, I'd like to call it using -performSelector. Here is the point, if the method dosen't return immediately I can't get the answer from the delegate.
I'm using NSInvocation to make that happen but is verbose, does exist some other way?

[UPDATE WITH CODE]
Pay attention that now I'm using invocation, the thread-check part is not still implemented. Commented there is the part that gave the warning

- (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");
}

[SORT OF SOLUTION STILL UNTESTED]

- (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;
}

Using the NSMethodSignature method, is possible to gear up, and ask for the return type. I still didn't test but it should made the trick.

Community
  • 1
  • 1
Andrea
  • 26,120
  • 10
  • 85
  • 131
  • 1
    Why do you need `performSelector` at all? If you have a delegate conforming to a protocol, you could call the method directly: `BOOL b = [self.delegate shouldLoadGameKitViewController:...]`. – Martin R Jun 03 '13 at 14:21
  • Because I have a method that before calling asks for the main thread, since you don't know where the block would be called. – Andrea Jun 03 '13 at 14:50
  • So you are replacing `performSelectorOnMainThread`? Perhaps you can show the relevant code, then it is easier to help. – Martin R Jun 03 '13 at 15:05
  • 1
    In example 2 stack overflow post, look at the answer which supresses the warning for that line of code. Use that. – bandejapaisa Jun 03 '13 at 15:12
  • possible duplicate of [performSelector may cause a leak because its selector is unknown](http://stackoverflow.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown) – jrturton Jun 03 '13 at 15:20
  • 1
    @jrturton That's not a duplicate read well the question, I'm not looking for a general solution to avoid warnings I've already read all the other questions – Andrea Jun 03 '13 at 15:39
  • @bandejapaisa thanks, I know.. use directly the runttime function I can avoid the warning, but (I mean ;-) ) is that possible that there isn't another friednly solution? – Andrea Jun 03 '13 at 15:47
  • @Andrea: It seems to me that you have 2 different problems: 1) Avoid the performSelector warning. That can be solved e.g. with NSInvocation . - 2) A threading problem. To execute the method on the main thread, you have to call `performSelectorOnMainThread` or `dispatch_(a)sync`. In both cases, the method cannot return a value to the calling thread *unless you wait* for the completion - but that can easily cause a deadlock. – Martin R Jun 03 '13 at 16:33
  • @MartinR Thank you.. yes, probably I've found a solution tomorrow I will post results – Andrea Jun 03 '13 at 19:49

2 Answers2

-1

Try to make this to avoid leak or "unknown selector send to instance" issue:

SEL selector = NSSelectorFromString(@"methodName::");
if ([obj respondsToSelector:selector])
    [obj performSelector:selector withObject@[args,array]];
-1

You can use dispatch_sync instead of dispatch_async to have the block performed immediately (your code will be blocked until the block returns).

Another alternative is to suppress the warning temporarily, as explained in this answer.

Community
  • 1
  • 1
Gerd K
  • 2,933
  • 1
  • 20
  • 23
  • In that way you would cause a deadlock http://stackoverflow.com/questions/10330679/how-to-dispatch-on-main-queue-synchronously-without-a-deadlock – Andrea Jun 03 '13 at 14:54
  • A `dispatch_async` may likely be performed immediately. The only difference between `async` and `sync` is that the block is guaranteed to execute fully before the latter returns. – bbum Jun 03 '13 at 15:34