从后台线程访问 [UIApplication sharedApplication] 可以吗?

Posted

技术标签:

【中文标题】从后台线程访问 [UIApplication sharedApplication] 可以吗?【英文标题】:Is it ok accessing [UIApplication sharedApplication] from background thread? 【发布时间】:2020-02-11 07:35:21 【问题描述】:

在处理Objective-C 时,我可能需要在一些后台线程中获取protectedDataAvailable 状态。

- (BOOL) isProtected 
    BOOL protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
    return protectedDataAvailable;

当我访问[UIApplication sharedApplication] 时,我怀疑代码块应该在主队列中运行。 我该怎么做?

我想改变它,

- (BOOL) isProtected 

    BOOL protectedDataAvailable = NO;

    dispatch_sync(dispatch_get_main_queue(), ^
        protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
    );

    return protectedDataAvailable;

问题 1:代码是否应该在主队列/UI 线程中运行?

问题 2:如果是,我更改的代码会解决问题吗?还是有更好的方法?

我问这个问题的原因是,即使我同步访问 主队列 上的UIApplication,当从main thread 调用块时,它也会崩溃。我该如何处理这个问题?

【问题讨论】:

【参考方案1】:

问题 1:代码是否应该在主队列/UI 线程中运行?

肯定是的,因为如果您在 Xcode 上使用主线程检查器运行您的应用程序,当从后台线程访问时,调用 UIApplication sharedApplication 会突出显示为问题

问题 2:如果是,我更改的代码会解决问题吗?

除非你从主线程调用isProtected 是的。

或者有没有更好的方法?

我会坚持这样的:

- (BOOL)isProtected

    __block BOOL protectedDataAvailable = NO;

    if ([NSThread isMainThread])
    
        protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
    
    else
    
        dispatch_sync(dispatch_get_main_queue(), ^

            protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
        );
    

    return protectedDataAvailable;

正如 Alejandro Ivan 在评论中指出的那样,您可以使用简单的dispatch_sync而不是使用信号量

【讨论】:

为什么将dispatch_async() 与信号量一起使用而不是仅仅使用dispatch_sync()?可以肯定的是,手动处理信号量很昂贵。我会使用- (BOOL)isProtected __block BOOL protectedDataAvailable = NO; dispatch_sync(dispatch_get_main_queue(), ^ protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable]; ); return protectedDataAvailable; @AlejandroIván 我同意。简单的 dispatch_sync 绝对是一个选项,至少有更少的代码,甚至(我不确定)更少的开销 主要区别在于 GCD 队列不使用锁(因此它们是单线程访问),但信号量确实使用它们(尽管轻量级互斥锁)。这使得信号量与多线程兼容。对于普通的 UI 应用程序,可能不需要信号量。 @AndreyChernukha 如果我使用dispatch_sync,我只需要删除与信号量相关的行,对吗?如果您更新代码以使用dispatch_sync,这将很有帮助。

以上是关于从后台线程访问 [UIApplication sharedApplication] 可以吗?的主要内容,如果未能解决你的问题,请参考以下文章

主线程检查器:在后台线程上调用的 UI API:-[UIApplication applicationState]

如何同时运行后台服务应用程序和 UIApplication

后台运行之[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]

- (void)applicationWillTerminate:(UIApplication *) 当应用程序从后台移除时应用程序没有调用

找出从后台线程访问的 winforms 控件

我需要从后台线程访问listview的适配器