如何运行一个非主队列处于后台状态?
How to run a non main queue in a background state?
请看一下这段非常简单的代码:
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i < 100; i++)
{
NSLog(@"LOOP %d", i);
sleep(1);
}
});
如果我将我的应用程序发送到后台状态,它仍然是 运行ning。但是,如果我像这样将执行放到非主队列中:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 0; i < 100; i++)
{
NSLog(@"LOOP %d", i);
sleep(1);
}
});
然后当我的应用程序进入后台时暂停执行。在非主队列上调度时是否可以使其 运行 处于后台状态?
我需要说明一下,我正在 运行我的应用程序启用了这些后台模式:
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>voip</string>
</array>
请尝试使用 NSProcessInfo performExpiringActivityWithReason
API
[[NSProcessInfo processInfo] performExpiringActivityWithReason:@"myReason" usingBlock:^(BOOL expired)
{
// This block is run on a separate (background) thread
// Put your code here...
}
请注意,这只是请求在后台运行的进程上额外 CPU 时间...您不能无限期地 运行 后台代码。
当你即将被杀死时,expired == YES
将第二次调用该块。
除了使用performExpiringActivityWithReason
,您还可以使用UIBackgroundTaskIdentifier
API:
// Perform the task on a background queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Request the task assertion and save the ID.
self.backgroundTaskID = [[UIApplication sharedApplication]
beginBackgroundTaskWithName: @"Finish Pending Tasks" expirationHandler:^{
// End the task if time expires.
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
self.backgroundTaskID = UIBackgroundTaskInvalid;
}];
// Add your code here.
// End the task assertion.
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
self.backgroundTaskID = UIBackgroundTaskInvalid;
};
到期处理程序是在应用程序被终止之前调用的,但不要计划使用此方法执行计算量大的任务,因为 OS 具有系统范围的时间限制,这超出了开发人员的范围控制。
如果您需要在后台为某些系统事件(如网络获取)执行特定任务,请考虑使用后台模式。
在这种情况下,使用 UIKit API 的优势是您可以在 for 循环中查询 [[UIApplication sharedApplication] backgroundTimeRemaining]
以执行任何最后一分钟的清理步骤。
请注意,如果您使用的是 App Extensions,Apple 建议使用 NSProcess
API,因此建议会因用例而异。
请看一下这段非常简单的代码:
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i < 100; i++)
{
NSLog(@"LOOP %d", i);
sleep(1);
}
});
如果我将我的应用程序发送到后台状态,它仍然是 运行ning。但是,如果我像这样将执行放到非主队列中:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 0; i < 100; i++)
{
NSLog(@"LOOP %d", i);
sleep(1);
}
});
然后当我的应用程序进入后台时暂停执行。在非主队列上调度时是否可以使其 运行 处于后台状态?
我需要说明一下,我正在 运行我的应用程序启用了这些后台模式:
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>voip</string>
</array>
请尝试使用 NSProcessInfo performExpiringActivityWithReason
API
[[NSProcessInfo processInfo] performExpiringActivityWithReason:@"myReason" usingBlock:^(BOOL expired)
{
// This block is run on a separate (background) thread
// Put your code here...
}
请注意,这只是请求在后台运行的进程上额外 CPU 时间...您不能无限期地 运行 后台代码。
当你即将被杀死时,expired == YES
将第二次调用该块。
除了使用performExpiringActivityWithReason
,您还可以使用UIBackgroundTaskIdentifier
API:
// Perform the task on a background queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Request the task assertion and save the ID.
self.backgroundTaskID = [[UIApplication sharedApplication]
beginBackgroundTaskWithName: @"Finish Pending Tasks" expirationHandler:^{
// End the task if time expires.
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
self.backgroundTaskID = UIBackgroundTaskInvalid;
}];
// Add your code here.
// End the task assertion.
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
self.backgroundTaskID = UIBackgroundTaskInvalid;
};
到期处理程序是在应用程序被终止之前调用的,但不要计划使用此方法执行计算量大的任务,因为 OS 具有系统范围的时间限制,这超出了开发人员的范围控制。
如果您需要在后台为某些系统事件(如网络获取)执行特定任务,请考虑使用后台模式。
在这种情况下,使用 UIKit API 的优势是您可以在 for 循环中查询 [[UIApplication sharedApplication] backgroundTimeRemaining]
以执行任何最后一分钟的清理步骤。
请注意,如果您使用的是 App Extensions,Apple 建议使用 NSProcess
API,因此建议会因用例而异。