Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using _cmd to perform method on main thread in objective c

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?

like image 561
Sean Danzeiser Avatar asked Nov 02 '12 06:11

Sean Danzeiser


2 Answers

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.

like image 125
yfrancis Avatar answered Nov 08 '22 05:11

yfrancis


_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.

like image 42
justin Avatar answered Nov 08 '22 05:11

justin