views:

236

answers:

1

Consider this:

@interface SomeViewController : UIViewController {
    SomeChildObject *child;
}
@end

@implementation SomeViewController

- (void) viewDidLoad {
    ...
    child.delegate = self;
}

- (void) somethingHappened {
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]
        initWithTarget:child
        selector:@selector(doSomething)
        object:nil];
[someNsOperationQueue addOperation:operation];
[operation release];
}

- (void) callbackA:(SomeData *)someData {
[self performSelectorOnMainThread:@selector(callbackAonMainThread:)
                       withObject:someData
                    waitUntilDone:NO];
}

- (void) callbackAonMainThread:(SomeData *)someData {
    ... do something with results in main thread, e.g UI feedback
}

- (void) callbackB:(SomeData *)someData {
[self performSelectorOnMainThread:@selector(callbackBonMainThread:)
                       withObject:someData
                    waitUntilDone:NO];
}

- (void) callbackBonMainThread:(SomeData *)someData {
    ... do something with results in main thread, e.g UI feedback
}


@end

In English:

I have a view controller running in the main thread with a child model object to do something (fetch data over network). The view controller is the delegate for the child, so the child can signal the results back with delegation. To perform the expensive work, I spawn the child.doSomething method with a NSInvocationOperation that launches the operation in a background thread. When done, the child calls the delegate's (view controller's) callbackA or callbackB with some results. Since (I think) these callbacks are invoked in the same background thread where the doSomething call was run, I need to call performSelectorOnMainThread to transfer control back to main thread.

This works fine, but I do not like having two callback-related methods for each callback. (There are actually more callbacks, so the real code is even more bloated.) Ideally, I would do something like this:

- (void) callbackA:(SomeData *)someData {
    if (not_running_on_main_thread) {
    [self performSelectorOnMainThread:@selector(callbackA:)
                       withObject:someData
                    waitUntilDone:NO];
    } else {
        // now running on main thread, work with the results.
    }
}

Questions:

1) how do I do the "not_running_on_main_thread" test?

2) is there any other way to cut down the callbacks bloat?

EDIT: ok, I never read NSThread docs before posting :) looks like [NSThread isMainThread] is what I am looking for. But is there any other way to restructure or make this nicer still?

+3  A: 

Just check for [NSThread isMainThread]. There's nothing more you can do if you need multiple callbacks which do different things.

Only one thing I do differently, my code looks like this:

- (void) callbackA:(SomeData *)someData {
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(callbackA:)
                       withObject:someData
                    waitUntilDone:NO];
        return;
    }

    // now running on main thread, work with the results.
}

This lets me get rid of the whole-function-long else and make the code a little clearer. And you can save on one indentation level this way ;-)

Adam Woś
Good tip for return. I like pretty code.
Jaanus