2014-01-15 26 views
4

我想说明的MBProgressHUD项目的进展情况,但是当我通过靶向这种方法:如何使用GCD演示背景任务?

- (IBAction)signInBttn:(id)sender { 

    MBProgressHUD *hudd = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; 
    hudd.mode = MBProgressHUDModeAnnularDeterminate; 
    hudd.labelText = @"Loading"; 

    __block float value = 0; 
    for (int j = 0; j<2000; j++) { 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

      for (int i = 0; i<20000 ; i++) { 

      } 
      value += 0.001; 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       hudd.progress = value; 
      }); 

     }); 
    }   
} 

HUD完全出现100%。这仅仅是为了我的信息,我不知道如何创建后台任务来计算某些事情,以及当他完成后, 40%的HUD令人耳目一新,达到了40%的进步。我希望我自己清楚,如果有人有时间来帮助改进我的代码,非常感谢任何答案

+0

相同的基本问题,因为[动态更新一个UILabel(http://stackoverflow.com/q/6336991/)的UI没有得到重新绘制,直到控制权返回到运行循环。正确的做法是使用某种计时器。 –

+0

空的'for'循环应该是“暂停”吗?编译器很可能会优化这种不存在的权利。 –

+0

是的,我想以简单的方式模拟高级计算 – user3163231

回答

3

在这种情况下,你可以从你的HUD在你的UI更新解耦计数器的更新解决的问题。 Apple在WWDC 2012视频Asynchronous Design Patterns with Blocks, GCD, and XPC中将此称为“异步更新状态”。

通常这不是必需的(大部分时间,我们正在异步做的事情足够慢,我们没有问题),但是如果做的事情比UI运行速度更快,希望能跟上与此同时,您为此创建了一个“调度源”。我打算用UIProgressView来说明,但同样适用于几乎任何UI:

// create source for which we'll be incrementing a counter, 
// and tell it to run the event handler in the main loop 
// (because we're going to be updating the UI) 

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); 

// specify what you want the even handler to do (i.e. update the HUD or progress bar) 

dispatch_source_set_event_handler(source, ^{ 
    self.iterations += dispatch_source_get_data(source); 
    [self.progressView setProgress: (float) self.iterations/kMaxIterations]; 
}); 

// start the dispatch source 

dispatch_resume(source); 

// now, initiate the process that will update the source 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    for (long i = 0; i < kMaxIterations; i++) 
    { 
     // presumably, do something meaningful here 

     // now increment counter (and the event handler will take care of the UI) 

     dispatch_source_merge_data(source, 1); 
    } 

    // when all done, cancel the dispatch source 

    dispatch_source_cancel(source); 
}); 

在我的例子,iterations只是一个long属性:

@property (nonatomic) long iterations; 

我定义我的kMaxIterations常数如下:

static long const kMaxIterations = 10000000l; 
0

首先,如果您想延迟执行,请使用dispatch_after:Apple Doc,因为可能是Clang是优化你的循环(即通过使它不存在)。

在该块内调用主线程上的dispatch_sync来更新UI,因为dispatch_async不保证“均匀”执行。像这样的东西应该工作...

for (...) { 
    dispatch_after(<some formula of i>, DEFAULT_PRIORITY, ^{ 
     dispatch_sync(MAIN_QUEUE, ^{ hudd.progress = value }); 
    } 
} 
+0

使用'dispatch_sync'工作,但将后台进程的速度限制在UI更新发生的速度。 – Rob