iOS的后台任务没有完成
据我了解,后台任务可以实现以执行需要比分配的3-4秒applicationDidEnterBackground
你使用像这样提供了更多的特定过程:iOS的后台任务没有完成
- (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;
});
}
不幸的是,我似乎在这里失去一些东西。虽然我收到Doing something...
这是从上面的代码是相当明显的,我从来没有收到任何种类的指示后台任务过期或曾经进入expirationHandler
正确完成任务。
我很困惑,“做某事”调度如何与后台任务相关,或者与任务相关联,让应用程序知道允许此过程在应用程序允许的〜10分钟内完成BG任务。
注意:我确保我已允许在我的info.plist中使用Background Modes
,因为许多发布的解决方案指出可能是其他人的问题。
如果有人可以帮助我正确地完成后台任务,我会非常感激。
FYI:这样做的主要目的是用查询更新我的Parse
数据库,以将用户新值(本地到设备)值设置为数据库。这是我会使用的情况下,我不是足够清楚:
// 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: 我曾试着拨打解析块内[application endBackgroundTask:bgTask];
但它不会被调用。有几次它假设这两次都是最快的,但我正在尝试处理更新Parse成功所需的时间比关闭应用程序所需的时间更长的情况。下面是我做的:
- (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;
}
}];
}];
});
}
你有正确的结构一般,除非你在呼唤从[application endBackgroundTask:self.backgroundTaskId];
您dispatch_async
块外,所以后台任务将会结束前的解析操作将完成。另外,如果您正在更新的用户是当前登录的用户,则可以使用PFUser.currentUser
而不必搜索。
所以,你应该applicationDidEnterBackground
是这样的:
- (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;
}];
});
}
到期处理程序,如果你的后台任务到期时才会调用。由于在过期之前调用'endBackgroundTask',处理程序将不会被调用。我怀疑你的问题是你在后台调度Parse活动,但接着调用'endBackgroundTask'。只有在更新完成后,才应该调用'endBackgroundTask'。 – Paulw11
好吧,很高兴知道。我仍然不确定如何让'dispatch_async'正确执行任务。例如,我试图让它在10分钟后为NSLog调用一个GCD,并且它从未被解雇。 –
它的工作原理很简单'做些什么......'但我无法完成任何需要超过应用程序终止时间的事情:\ –