3

I have a method like:

- (BOOL)shouldDoSomeWork {
   BOOL result = // here I need do hard work with data in background thread and return result, so main thread should wait until the data is calculated and then return result;
   return result;
}

How to implement that?

James Webster
  • 31,873
  • 11
  • 70
  • 114
Jim
  • 8,874
  • 16
  • 68
  • 125
  • 1
    If you want to process something in the background, you can't return the result like this. You'll have to use a delegate or blocks (like an anonymous function). – Andreas Ley Oct 12 '12 at 12:23
  • 2
    You say that you want the main thread to wait on this new thread. If it does that, there's no point in making a thread. Just use the method as you have it here. – James Webster Oct 12 '12 at 12:23
  • The reason of this is that I want to start activityIndicator, and then do some hard work. If to do hard work on main thread, activity Indicator do not want to be visible – Jim Oct 12 '12 at 12:27
  • @Jim Any GUI interaction (such as starting the activity indicator) has to be done on the main thread. You should go with James's method, and at the end call [self performSelectorOnMainThread..] and pass the result using this method. – mota Oct 12 '12 at 12:30

4 Answers4

5

Are you looking for this:

-(void) startWork
{ 
    //Show activity indicator
    [NSThread detachNewThreadSelector:@selector(doSomeWork) toTarget:self withObject:nil];
}

-(void) doSomeWork
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    //Do your work here
    [pool release];
    [self performSelectorOnMainThread:@selector(doneWork) withObject:nil waitUntilDone:NO];
}  

-(void) doneWork
{
   //Hide activity indicator  
}
James Webster
  • 31,873
  • 11
  • 70
  • 114
5

Example how to do it with GCD:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // Your hard code here
        // ...

        //BOOL result = ...

        dispatch_async(dispatch_get_main_queue(),^{
            [self callbackWithResult:result];  // Call some method and pass the result back to main thread
        });

    });
onegray
  • 5,105
  • 1
  • 23
  • 29
1

Common advice is to use the highest level of abstraction available to you to perform a task. As such NSThread should be relatively low down in the list of things you can do to execute work in the background.

The order you investigate APIs should be like this:

  1. NSOperation / NSOperationQueue
  2. Grand Central Dispatch (libdispatch)
  3. NSThread
  4. POSIX threads

With the first two you write your code as a "unit of work" and then put this work on a queue to be executed at some point. The system takes care of creating and destroying threads for you and the APIs are easy to work with. Here's an example using NSOperationQueue.

NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    //Do work


    //update your UI on the main thread.
    [self performSelectorOnMainThread:@selector(workDone:) withObject:workResults waitUntilDone:NO];
}];

[self.operationQueue addOperation:blockOperation];

easy as that.

Community
  • 1
  • 1
jackslash
  • 8,550
  • 45
  • 56
1

That's not typically how you would do it. You need something structured more like this:

- (void)doSomeWorkAndThen:(^void)block {
  dispatch_async(dispatch_get_global_queue(0, 0), ^ {
    // do
    // some
    // work
    dispatch_sync(dispatch_get_main_queue(), ^ {
      block();
    });
  }); 

That is, you keep the request and what you do afterwards in one place.

Stephen Darlington
  • 51,577
  • 12
  • 107
  • 152
  • 1
    which is fine until you pass NULL for the completion block. Your code could be made better by following platform naming conventions, e.g. `-(void)doSomeWorkWithCompletionHandler:(void (^)(void))completion;` – jackslash Oct 12 '12 at 12:46
  • Absolutely, I was intending to show the structure rather than providing code to copy and paste... – Stephen Darlington Oct 12 '12 at 14:09