2010-10-07 2 views
12

Я пытаюсь использовать метод из класса, который я загрузил где-то. Метод выполняется в фоновом режиме, пока выполнение программы продолжается. Я не хочу, чтобы выполнение программы продолжалось до тех пор, пока этот метод не завершится. Как мне это сделать?Как дождаться окончания потока в Objective-C

ответ

0

Я бы предложил включить вызов метода класса в свой собственный метод и установить логическое значение после его завершения. Для например:

BOOL isThreadRunning = NO; 
- (void)beginThread { 
    isThreadRunning = YES; 

    [self performSelectorInBackground:@selector(backgroundThread) withObject:nil]; 
} 
- (void)backgroundThread { 
    [myClass doLongTask]; 

    // Done! 
    isThreadRunning = NO; 
} 
- (void)waitForThread { 
    if (! isThreadRunning) { 
     // Thread completed 
     [self doSomething]; 
    } 
} 

Как вы хотите обрабатывать ожидания до вас: Возможно, опрос с [NSThread sleepForTimeInterval: 1] или аналогичный, или отправив сообщение и настраивает каждый цикл выполнения.

+0

Я сделал это, и он работает, но также предотвращает отображение HUD. –

+0

Вы можете использовать NSTimer для опроса и сохранения обновлений пользовательского интерфейса. Все зависит от того, что вам нужно. Для простой задачи, а затем обновить ответ Дерека будет более аккуратным и менее хлопотным. – v01d

+0

Для игрового движка или чего-то большего в реальном времени таймер может быть уже на месте. Затем, отправляя поток и забывая о нем, может быть больше, что вам нужно. – v01d

6

Мое первое желание - не делать то, что вы предлагаете. Техника, которую я использовал ранее, - это дать потоку селектор методу в исходном объекте (который находится в основном потоке). Когда второй поток запущен, основной поток продолжает выполняться, но на дисплее отображает индикатор занятости. Это позволяет при необходимости взаимодействовать с пользователем.

Когда вторая нить заканчивается, перед ее выключением она вызывает селектор в основном потоке. Метод, который ссылается на селектор, затем удаляет индикатор занятости с дисплея и сообщает основному потоку обновляться, собирая все данные, которые генерировал второй поток.

Я успешно использовал это приложение, которое обращается к веб-службе (во втором потоке), а затем обновляет отображение после возвращения данных без его блокировки. Это значительно улучшает работу пользователя.

+1

Это хорошая система для обновлений пользовательского интерфейса; они могут быть болью. – v01d

8

Используйте NSOperationQueue, как это
(из памяти так что простите любые незначительные ошибки - вы получите основную идею):


// ivars 
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; 
// count can be anything you like 
[opQueue setMaxConcurrentOperationCount:5]; 

- (void)main 
{ 
    [self doStuffInOperations]; 
} 

// method 
- (void)doStuffInOperations 
{ 
    // do parallel task A 
    [opQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"a"] autorelease]]; 

    // do parallel task B 
    [opQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"b"] autorelease]]; 

    // do parallel task C 
    [opQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"c"] autorelease]]; 


    [opQueue waitUntilAllOperationsHaveFinished]; 

    // now, do stuff that requires A, B, and C to be finished, and they should be finished much faster because they are in parallel. 
} 

- (void)doSomething:(id)arg 
{ 
    // do whatever you want with the arg here 
    // (which is in the background, 
    // because all NSOperations added to NSOperationQueues are.) 
} 


+1

Я знаю, что я не задавал этот вопрос, но это было то, что я искал с помощью своего приложения, потому что у меня были условия гонки, и я знал, что это потому, что я мог быстрее нажимать код, чтобы закончить, таким образом, состояние частичной нагрузки на представления , Это решило мою проблему большое время. Так что спасибо вам, сэр, я чувствую, что это должно быть отмечено как истинный ответ, потому что он не использует работу и включает потокобезопасное кодирование с библиотекой ios. – Rob

+0

Во-вторых, что Роб сказал, это именно то, что я искал тоже! – AdamM

+1

@AdamM - ознакомьтесь с другим ответом, который я разместил сегодня. Это гораздо более чистый способ сделать это, и GCD поддерживается для всех iOS 4 и выше. Одним из важных преимуществ этого способа является то, что вы не получите сбоев, когда объекты будут освобождены из-под вас, потому что GCD автоматически сохраняет и освобождает весь объект, который вы ссылаетесь. – jpswain

35

Вот еще один способ сделать это с помощью НОД:



- (void)main 
{ 
    [self doStuffInOperations]; 
} 

- (void)doStuffInGCD 
{ 
    dispatch_group_t d_group = dispatch_group_create(); 
    dispatch_queue_t bg_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

    dispatch_group_async(d_group, bg_queue, ^{ 
     [self doSomething:@"a"]; 
    }); 

    dispatch_group_async(d_group, bg_queue, ^{ 
     [self doSomething:@"b"]; 
    }); 

    dispatch_group_async(d_group, bg_queue, ^{ 
     [self doSomething:@"c"]; 
    }); 


    // you can do this to synchronously wait on the current thread: 
    dispatch_group_wait(d_group, DISPATCH_TIME_FOREVER); 
    dispatch_release(d_group); 
    NSLog(@"All background tasks are done!!"); 


    // **** OR **** 

    // this if you just want something to happen after those are all done: 
    dispatch_group_notify(d_group, dispatch_get_main_queue(), ^{ 
     dispatch_release(d_group); 
     NSLog(@"All background tasks are done!!");   
    }); 
} 

- (void)doSomething:(id)arg 
{ 
    // do whatever you want with the arg here 
} 
+4

Приветствия! Этот метод еще лучше – AdamM

+0

+1 для правильного ответа. – Abizern

+0

@node ninja Не могли бы вы выбрать ответ на свой вопрос? – jpswain

0

Мой метод, чтобы проверить, если задача может работать (если фоновый поток завершается), и если он не может работать, то я использую НОД, чтобы попробовать еще раз после задержки:

- (void)doSomething 
{ 
    if (/* is the other thread done yet? */) { 
    double delayInSeconds = 2.0; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
     [self doSomething]; 
    }); 
    return; 
    } 

    // do something 
} 
1

Несколько технических способов синхронизации многопотоков, таких как NSConditionLock (mutex-lock), NSCondition (семафор). Но они являются общим знанием программирования для других языков (java ...), кроме объектива-c. Я предпочитаю, чтобы ввести run loop (специальный в какао) осуществлять нить присоединиться:

NSThread *A; //global 
A = [[NSThread alloc] initWithTarget:self selector:@selector(runA) object:nil]; //create thread A 
[A start]; 

- (void)runA  
{ 
  [NSThread detachNewThreadSelector:@selector(runB) toTarget:self withObject:nil]; //create thread B  
  while (1)  
  {  
    if ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) //join here, waiting for thread B  
    {  
      NSLog(@"thread B quit...");  
      break;  
    }  
  }  
} 

- (void)runB  
{  
  sleep(1);  
  [self performSelector:@selector(setData) onThread:A withObject:nil waitUntilDone:YES modes:@[NSDefaultRunLoopMode]];  
} 
3

В таких случаях я обычно используя класс NSCondition.

//this method executes in main thread/queue 
- (void)waitForJob 
{ 
    id __weak selfWeak = self; 
    NSCondition *waitHandle = [NSCondition new]; 
    [waitHandle lock]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 
     [selfWeak doSomethingLongtime]; 
     [waitHandle signal]; 
    }); 
    //waiting for background thread finished 
    [waitHandle waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]]; 
} 
Смежные вопросы