iOS 后台任务未完成

标签 ios parse-platform task background-process

我知道可以实现后台任务来执行某些需要超过分配的 3-4 秒的进程 applicationDidEnterBackground 让你使用这样的东西:

- (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,因为许多已发布的解决方案指出可能是其他人的问题。

如果有人可以帮助我正确地完成后台任务,我将不胜感激。

仅供引用:这样做的主要目的是使用查询更新我的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.");
        }
   }];
}];

更新: 我试图在 Parse block 中调用 [application endBackgroundTask:bgTask]; 但它没有被调用。有几次它确实假设这两次都是最快的,但我正在尝试处理成功更新 Parse 将比关闭应用程序花费更长的时间的情况(除了那些 2 之外的所有情况)。这是我所做的:

- (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 block 之外,所以后台任务将是在解析操作完成之前结束。此外,如果您正在更新的用户是当前登录的用户,您可以使用 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;
        }];


    });
}

关于iOS 后台任务未完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34280060/

相关文章:

ios - 在 Swift 中设置 UIButton Image - 当前解包为 nil

android - iOS 和 Android 都支持 Boost C++ 线程吗?

cordova - Parse.com 推送通知未在 Android 后台显示

ios - Swift 3.2 iOS - 如何增加 Firebase MutableData 对象的 NSNumber?

iphone - 如何在 objective-c 中将gps north和gps west转换为lat/long

ios - 通过用户 ID 或某个唯一 ID :Issue 获取 PFInstallation

java - Android、Mandrill 和 Parse.com : Java ClassCastException: HashMap cannot be cast to a class

c# - Task.WaitAny 接受 Task<T> 而不是 Task [ ]

typescript - VS 代码 : watch typescript on save file

c# - UnobservedTaskException 没有终止进程