Reputation: 21808
Please take a look at this very simple piece of code:
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i < 100; i++)
{
NSLog(@"LOOP %d", i);
sleep(1);
}
});
If I send my app to the background state it is still running. Yet if I put the execution onto a non main queue like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 0; i < 100; i++)
{
NSLog(@"LOOP %d", i);
sleep(1);
}
});
then the execution is suspended when my app is going to the background. Is it possible to make it run in a background state when dispatched on a non main queue?
I need to mention that I'm running my app with these background modes enabled:
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>voip</string>
</array>
Upvotes: 1
Views: 432
Reputation: 9915
In addition to using performExpiringActivityWithReason
, you can use the 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;
};
The expiration handler is what gets called before the app is killed, but don’t plan on doing computationally expensive tasks using this method since the OS has system-wide time limits which are out of the developer’s control.
If you need to perform specific tasks in the background for certain system events like network fetches, then consider using a Background Mode.
The advantage of using the UIKit API, in this case, is you can query [[UIApplication sharedApplication] backgroundTimeRemaining]
within your for loop to perform any last-minute cleanup steps.
Note that if you’re using App Extensions Apple recommend using the NSProcess
API, so advice will vary depending on the use case.
Upvotes: 2
Reputation: 13458
Please try using NSProcessInfo performExpiringActivityWithReason
API
[[NSProcessInfo processInfo] performExpiringActivityWithReason:@"myReason" usingBlock:^(BOOL expired)
{
// This block is run on a separate (background) thread
// Put your code here...
}
please note this is only a request for some additional CPU time on a process that is being backgrounded ... you cannot run background code indefinitely.
The block will be invoked a 2nd time with expired == YES
when you're about to be killed.
Upvotes: 1