Georg Schölly
Georg Schölly

Reputation: 126085

How to use native C types with performSelectorOnMainThread:?

I'd like to call (void)setDoubleValue:(double)value using performSelectorOnMainThread:.

What I thought would work is:

NSNumber *progress = [NSNumber numberWithDouble:50.0];
[progressIndicator performSelectorOnMainThread:@selector(setDoubleValue:)
                                    withObject:progress
                                 waitUntilDone:NO];

Didn't work.

Then I implemented a helper method:

- (void)updateProgressIndicator:(NSNumber *)progress
{
    [progressIndicator setDoubleValue:[progress doubleValue]];
}

Works, but not really clean.

After that I tried it with NSInvocation.

NSInvocation *setDoubleInvocation;;
SEL selector = @selector(setDoubleValue:);
NSMethodSignature *signature;
signature = [progressIndicator methodSignatureForSelector:selector];
setDoubleInvocation = [NSInvocation invocationWithMethodSignature:signature];
[setDoubleInvocation setSelector:selector];
[setDoubleInvocation setTarget:progressIndicator];

double progress = 50.0;
[setDoubleInvocation setArgument:&progress atIndex:2];

[setDoubleInvocation performSelectorOnMainThread:@selector(invoke)
                                      withObject:nil
                                   waitUntilDone:NO];

This solution works, but it uses a lot of code and is quite slow. (Even if I store the invocation.)

Is there any other way?

Upvotes: 3

Views: 3541

Answers (4)

Jim Witte
Jim Witte

Reputation: 100

This blog post: http://www.cimgf.com/2008/03/01/does-objective-c-perform-autoboxing-on-primitives/ points out that while Cocoa won't autobox primitives, it will unbox them automatically. So numbers and BOOLs at least can be passed in as an NSNumber class, and the called function will automatically unbox it. I've been playing with using a proxy object (Uli's UKMainThreadProxy*) which works quite well, although I'm sure it has it's limitations like anything else.

Upvotes: -2

Brad Larson
Brad Larson

Reputation: 170309

Dave Dribin has a solution for this that takes the shape of a category on NSObject. His category wraps the method call in an NSInvocation and invokes that on the main thread. This way, you can use whatever method interface you like, including primitive types for your arguments.

The Amber framework also has a category on NSObject that adds a main thread proxy, where any messages sent to that proxy are executed on the main thread.

Upvotes: 2

bbum
bbum

Reputation: 162712

If you are on Snow Leopard, you can use Blocks:

dispatch_async(dispatch_get_main_queue(), ^{
    [progressIndicator setDoubleValue: 50.0];
});

Upvotes: 9

Ben Gottlieb
Ben Gottlieb

Reputation: 85522

you'll need to write a custom un-boxing method to wrap setDoubleValue:.

- (void) setDoubleValueAsNumber: (NSNumber *) number {
   [self setDoubleValue: [number doubleValue]];
}

Upvotes: 7

Related Questions