如何在后台线程和主线程之间切换

时间:2019-07-08 05:11:19

标签: objective-c multithreading user-interface

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

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

在代码产生(字符串)输出的几个地方,我通过调用如下所示的'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代码,而让主线程在计时器上每秒大约调用一次此代码?

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

1 个答案:

答案 0 :(得分:0)

可以使用 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