使用NSOperationQueue在线程之间移动变量

时间:2016-06-14 14:28:56

标签: ios objective-c thread-safety objective-c-blocks nsoperationqueue

背景

我有一个单例对象,它在后台线程上执行网络请求(通过NSOperationQueue创建)。这很好用。网络请求发生时不会堵塞用户界面。

问题

单身人士需要在后台网络请求期间拨打[UIApplication sharedApplication]。此调用检索有关应用程序状态的信息。 UIKit返回的值决定了应用程序的进展方式。当然,UIKit不是线程安全的,只能从主线程调用。因此,需要在主线程上完成对app状态信息的请求。

问题是这个包含app状态信息的变量是在主线程上设置的,但是需要在不同的线程上访问。 处理此问题的最佳方式是什么?

尝试解决方案(1)

此解决方案导致编译器错误。无法在块内修改appStateIsInForeground

 // Create variable on separate background thread

 // Configure the server connection based on the current app state
BOOL appStateIsInForeground = YES;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) appStateIsInForeground = YES;
    else appStateIsInForeground = NO;
}];

// Access appStateIsInForeground variable from the same separate background thread

尝试解决方案(2)

添加__block说明符会使编译器错误无效。但是,我觉得这个解决方案可能会导致竞争条件或抛出异常,因为尝试访问多个线程上的变量。

 // Create variable on separate background thread

 // Configure the server connection based on the current app state
__block BOOL appStateIsInForeground = YES;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) appStateIsInForeground = YES;
    else appStateIsInForeground = NO;
}];

// Access appStateIsInForeground variable from the same separate background thread

TL; DR

如何在后台线程上创建变量(使用NSOperationQueue初始化),在主线程上为其赋值,然后在原始后台线程上读取其值,而不会产生竞争条件或导致线程安全异常?

编辑:虽然在非主线程上读取来自UIKit的值可能是安全的,但这个问题可能仍有更广泛的应用。

1 个答案:

答案 0 :(得分:1)

我并不是百分之百确定在后台线程上只读取UIKit的值是个坏主意,但是如果它确实如此,那么使用好的dispatch_sync可能是合理的。功能

__block BOOL appStateIsInForeground = YES;

dispatch_sync(dispatch_get_main_queue(), ^{

    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) appStateIsInForeground = YES;
    else appStateIsInForeground = NO;
});