Using _cmd to perform method on main thread in objective c
Asked Answered
R

2

7

I came across this _cmd trick:

-(void)methodToBeRunOnMainThreadWithObj:(id)object {
    if (![NSThread isMainThread) {
        [self performSelectorOnMainThread:_cmd withObject:object]
    } else {
        // ... method body
    }
}

Is this a reliable way to ensure a method is performed on the main thread?

Robey answered 2/11, 2012 at 6:14 Comment(0)
S
7

This works, but is a bit of an anti-pattern. What I would do is throw an error if the thread the method is called on is not the main thread. It is the responsibility of the caller to make sure methods are called on the right threads, these sorts of hacks only encourage ugly code. Besides, if you rely on this, suddenly you're doubling the message dispatch overhead for every time you call this method.

If you really cant change the caller's behavior, you can try the following:

-(void)methodToBeRunOnMainThreadWithObj:(id)object {
    dispatch_sync(dispatch_get_main_queue(), ^{
        // code goes here
    });
}

this will cause all code inside the dispatch block to be executed on the main thread, and the method will not return until it is complete. If you want the method to return immediately, you can use dispatch_async instead. If you use dispatch_sync, you can use this trick even on methods that have non-void return types.

This code also has the added benefit of supporting methods with arguments that are of non-object types (int etc). It also supports methods with an arbitrary number of arguments, whereas performSelector:withObject: and its sibling methods only support a limited number of arguments. The alternative is to set up NSInvocation objects and those are a pain.

Note that this requires Grand Central Dispatch (GCD) on your platform.

Spannew answered 2/11, 2012 at 6:20 Comment(0)
W
3

_cmd forwarding is fine, as long as the selector specified by _cmd matches the definition/signature specified in the documentation: "The method should not have a significant return value and should take a single argument of type id, or no arguments.". If it does not match, then you should assume Undefined Behavior. And to be 110% safe and to adhere to the abstract machine, the return type should be id (or some objc-type), and the result should not return an owning reference.

Wallinga answered 2/11, 2012 at 6:25 Comment(2)
+1 for noting the restrictions. I ignored the return type issue in my answer because the original method in the question is a void, but OP seems to be looking for a general solution, and performSelector is not one.Spannew
@Spannew i initially avoided mentioning the return type as well :) but i added a bit about that in an edit.Wallinga

© 2022 - 2024 — McMap. All rights reserved.