Ahmed
Ahmed

Reputation: 15039

How to do a long operation on background thread and then later update UI on main thread

I have to do a IO operation which might take long to complete. The IO oeration is invoked from a button. Ofcourse the UI hangs untill the operation completes. So I suppose I need to do IO on some background thread, but when the operation completes I have to update window's labels to signal the operation complete. Which I suppose I should be doing on the main thread (like EDT in java and similar in C#) , correct ?

in C# there is class something like TaskAsync and similar in Java android. Which lets you complete the long task in another thread and the when the task is complete a handler is called on main thread , so that UI can be updated on main thread,

What exactly does cocoa has to do similar task, that is allow a long operation on seperate thread than main and then somehow facilitate to update the userinterface on main thread.

Upvotes: 0

Views: 1306

Answers (2)

Michael Dautermann
Michael Dautermann

Reputation: 89509

Assuming you have a handle to the view controller where you want to update the UI, you could use the NSObject "performSelectorOnMainThread:withObject:waitUntilDone:" method.

2) you could also utilize Grand Central Dispatch with code like this:

dispatch_async(dispatch_get_main_queue(), ^{
    [viewController doSomethingWhenBigOperationIsDone];
}); 

3) Or you could even post an NSNotification from your background thread where the observer (in the main thread) could update the UI.

You might find some additional useful information in this related question.

Upvotes: 0

iain
iain

Reputation: 5683

Your long running operation should be moved to an NSOperation subclass

AhmedsOperation.h

@interface AhmedsOperation : NSOperation

@end

AhmedsOperation.m

@implementation AhmedsOperation

// You override - (void)main to do your work
- (void)main
{
    for (int i = 0; i < 1000; i++) {
        if ([self isCancelled]) {
            // Something cancelled the operation
            return;
        }

        sleep(5);

        // Emit a notification on the main thread
        // Without this, the notification will be sent on the secondary thread that we're
        // running this operation on
        [self performSelectorOnMainThread:@(sendNotificationOnMainThread:)
                               withObject:[NSNotification notificationWithName:@"MyNotification"
                                                                        object:self
                                                                      userInfo:nil]
                            waitUntilDone:NO];
    }
}

- (void)sendNotificationOnMainThread:(NSNotification *)note
{
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc postNotification:note];
}

Then in your main code, when you want to do your operation you just create an AhmedsOperation object, and push it to an NSOperationQueue and listen to the notifications.

AhmedsOperation *op = [[AhmedsOperation alloc] init];
NSOperationQueue *defaultQueue = [MLNSample defaultOperationQueue];

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
       selector:@selector(progressUpdateNotification:)
           name:@"MyNotification"
         object:op];

[defaultQueue addOperation:op]; 

Upvotes: 1

Related Questions