【问题标题】:How to switch between background and main threads如何在后台线程和主线程之间切换
【发布时间】:2019-11-17 14:28:20
【问题描述】:

我以前从未使用过后台线程。我目前在主线程上运行一个耗时的计算,它将数据输出附加到 TERecord。我的工作流程基本上是:

运行漫长的过程... 更新界面… 运行漫长的过程... 更新界面… 等等。

在代码产生(字符串)输出的几个地方,我通过调用此处显示的“addToRecord”方法来更新 UI:

-(void)addToRecord:(NSString*)passedStr:(BOOL)updateUI
 {
    NSRange endRange;
    // add the passed text...
    endRange.location = [[theOutputView textStorage] length];
    endRange.length = 0;
    [theOutputView replaceCharactersInRange:endRange withString:passedStr];

if(updateUI) // immediate GUI update needed...
    {
    // scroll window contents to BOTTOM of page...
    endRange = NSMakeRange([[theOutputView string] length],0);
    [theOutputView scrollRangeToVisible:endRange];

    [theOutputView display];
    }
}

当然,虽然它完成了这项工作,但我的整个 UI 仍然没有响应,直到该过程完成。我知道我应该在我以前从未使用过的后台线程上做繁重的工作。我在创建如下后台线程时发现了部分问题:

-(IBAction)readUserInput:(id)sender
{   
// irrelevant code snipped for brevity
if([self checkForErrors] == NO)
    {
    [runButton setEnabled:NO];
    [self performSelectorInBackground:@selector(runWorkThread)     withObject:nil];
    }
}

-(void)runWorkThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    [self runLongProcess];
[pool drain];
}

但是我只是不明白每次代码遇到我的'addToRecord'方法时如何调用主线程,那么如何将控制权返回给后台线程? 另一种可能性可能是从我的“addToRecord”方法中删除 updateUI 代码,并让主线程每隔一秒左右在计时器上调用此代码?

任何建议和示例代码将不胜感激。谢谢!

【问题讨论】:

  • 你好,只是想和你澄清一下你的问题,你想在runLongProcess完成后,你想填充一些东西还是通知在主线程上调用-(void)addToRecord:(NSString*)passedStr:(BOOL)updateUI
  • @HSG。当我在主线程上运行长进程时,它在进程结束之前调用了大约十几次“addToRecord”。每次这都会向 NSTextView 绘制额外的文本并以连续滚动动作更新 UI。我想从我的后台线程中删除此方法的“updateUI”部分,让它只是将附加文本附加到 TERecord 并以某种方式让主线程更新 UI 并显示它。如果在后台进程运行时(几分钟)我无法更新 UI 至少 2-3 次,空白文本视图会使其看起来像应用程序已停止。

标签: objective-c multithreading user-interface


【解决方案1】:

您可以使用 Dispatch 框架(也称为 GCD)代替 performSelectorInBackground,这是处理并发工作的首选方式。 Dispatch 已经设置了一个可以使用的后台线程池。要切换线程,您可以像这样调用dispatch_async()

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
        // :
        // Do your background work here
        // :
        dispatch_async(dispatch_get_main_queue(), ^{
            // :
            // Now you are back in the main thread
            // :
        });
    });

第一个参数是由dispatch_get_global_queue() 提供给您的队列标识符,它返回一个“工作”队列,或者dispatch_get_main_queue() 返回主队列。最后一个参数是在所选队列上执行的代码块。

当使用dispatch_get_global_queue() 请求并发队列时,您指定服务质量,它决定了您的代码相对于其他工作的优先级。有关更多信息和可能的值,请参阅文档。

Read more on the Dispatch

【讨论】:

  • 谢谢。它现在正按我想要的方式工作(而且 GCD 似乎使用起来更简单,没有水池等)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
  • 1970-01-01
相关资源
最近更新 更多