Reputation: 2228
I understand that background tasks can be implemented to perform certain processes that need more than the allotted 3-4 seconds applicationDidEnterBackground
gives you using something like such:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up your background stuff
NSLog(@"Finsihed background task.");
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Begin your background stuff...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do something...like update Parse DB
NSLog(@"Doing something...");
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
Unfortunately, I seem to be missing something here. While I am receiving Doing something...
which is fairly obvious from the above code, I am never receiving any sort of indication that the background task expires or ever enters the expirationHandler
to properly finish the task.
I am confused first off how the "do something" dispatch is even related to the background task, or is linked with the task to let the application know to allow this process to complete in the ~10 minutes the application allows for BG Tasks.
NOTE: I have ensured that I have allowed for Background Modes
in my info.plist, as many posted solutions point out may be the problem for others.
If someone can help me properly allow a background task to be completed I would most appreciative.
FYI: The main purpose of this is to update my Parse
database with a query to set the users new (local to the device) values to the DB. This is what I would be using in case I am not being clear enough:
// Do something...like update Parse DB
NSLog(@"Doing something...");
. . .
PFQuery *query = [PFQuery queryWithClassName:@"_User"];
// Retrieve the object by id
[query getObjectInBackgroundWithId:<SOME_OBJECT_ID> block:^(PFObject *userInfo, NSError *error) {
// Save user info to current user info on Parse
[userInfo saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Could not update Parse with error: %@", error);
}
else {
NSLog(@"Updated Parse successfully.");
}
}];
}];
UPDATE:
I have tried to call [application endBackgroundTask:bgTask];
within the Parse block but it does not get called. A few times it did assuming it was quickest both of those times, but I am trying to handle situations (like all but those 2) where updating Parse successfully will take longer than the closing the application. Here is what I did:
- (void)applicationDidEnterBackground:(UIApplication *)application {
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
NSLog(@"Good for you.");
}
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId];
NSLog(@"done");
}];
// Begin your background stuff...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do something...like update Parse DB
NSLog(@"Doing something...");
PFQuery *query = [PFQuery queryWithClassName:@"_User"];
// Retrieve the object by id
[query getObjectInBackgroundWithId:<SOME_OBJECT_ID> block:^(PFObject *userInfo, NSError *error) {
// Save user info to current user info on Parse
userInfo[@"test"] = [NSNumber numberWithInteger:12345];
[userInfo saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Could not update Parse with error: %@", error);
[application endBackgroundTask:self.backgroundTaskId];
self.backgroundTaskId = UIBackgroundTaskInvalid;
}
else {
NSLog(@"Updated Parse successfully.");
[application endBackgroundTask:self.backgroundTaskId];
self.backgroundTaskId = UIBackgroundTaskInvalid;
}
}];
}];
});
}
Upvotes: 2
Views: 411
Reputation: 114836
You have the right structure generally, except that you are calling [application endBackgroundTask:self.backgroundTaskId];
from outside your dispatch_async
block, so the background task will be ended before the Parse operations will complete. Also, if the user your are updating is the currently logged in user, you can use PFUser.currentUser
rather than having to search.
So, your applicationDidEnterBackground
should be something like:
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up your background stuff
NSLog(@"Expired background task.");
[application endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
// Begin your background stuff...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Doing something...");
// Do something...like update Parse DB
PFUser *user=[PFUser currentUser];
// Update User fields as required
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
if (succeeded) {
NSLog(@"Saved user");
} else {
NSLog(@"Error:%@",error.localizedDescription);
}
NSLog(@"Background time remaining=%f",UIApplication.sharedApplication.backgroundTimeRemaining);
[application endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
});
}
Upvotes: 1