【问题标题】:Using multiple beginBackgroundTaskWithExpirationHandler calls使用多个 beginBackgroundTaskWithExpirationHandler 调用
【发布时间】:2012-03-11 22:14:59
【问题描述】:

我正在尝试在这里关注之前的帖子:Best practice to send a lot of data in background on iOS4 device?

基本上,我有一个名为 getRequest 的方法,它可以从 Web 服务器获取信息。我需要来自 Web 服务器的大约 50 条数据。所以同时,我有 50 个委托调用 connectionDidFinishLoading。目前我的 getRequest 看起来像:

-(void) getRequestWithURL:(NSString *) requestURL 
{
    static int getRequest = 0;
    NSLog(@"getRequest: %i", getRequest);
    getRequest++;

    UIApplication *app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier taskID;
    taskID = [app beginBackgroundTaskWithExpirationHandler:^{

        NSLog(@"Time remaining: %f", app.backgroundTimeRemaining);

        NSLog(@"Background task not completed");
        [app endBackgroundTask:taskID];
    }];

    NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:requestURL]];
    NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:req delegate:self] ; 
    [self startRequestWithConnection:con];
    [req release];

    if (taskID == UIBackgroundTaskInvalid) {
        NSLog(@"Failed to create background task identifier");
    }

}

然后在我的connectionDidFinishLoading中:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
        // process data from server
   // endBackgroundTask:someTaskID???
}

我知道您可以多次调用 beginBackgroundTaskWithExpirationHandler,但我不知道我在 getRequest 方法中所做的是否正在这样做,因为每次调用该方法时我只有一个变量 __block UIBackgroundTaskIdentifier taskID。而且我也不确定是否需要在每次调用 getRequest 时在 connectionDidFinishLoading 方法中调用 endBackgroundTask,因为您应该平衡 beginBackgroundTaskWithExpirationHandler 与 endBackgroundTask: 调用。如果是这样,我该怎么做,因为我的 getRequest 目前没有那个基础设施?我是否需要 50 个 ivars 才能让 connectionDidFinishLoading 方法看到对 getRequest 的 50 个初始调用?谢谢。

【问题讨论】:

  • 这里的任务是什么? backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; backgroundTaskID = UIBackgroundTaskInvalid; }];这只是返回一个背景 ID,但实际的方法调用在哪里?

标签: iphone


【解决方案1】:

正如您所说,您需要平衡beginBackgroundTaskWithExpirationHandler 呼叫与endBackgroundTask 呼叫。

我想到的一个解决方案如下所示:

创建一个新的实例变量

UIBackgroundTaskIdentifier backgroundTaskID;

您仍然在计算请求,因此您也可以在 connectionDidFinishLoading 中减少 getRequest:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // process data from server
    getRequest--;

    if (getRequest == 0 && backgroundTaskID != UIBackgroundTaskInvalid)
    {
        [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
        backgroundTaskID = UIBackgroundTaskInvalid;
    }
}

现在后台任务在最后一个请求完成后结束。要仅启动一个后台任务,您可以在应用程序进入后台时调用的方法启动它。

你需要收听UIApplicationDidEnterBackgroundNotification

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(applicationDidEnterBackground)
                                             name:UIApplicationDidEnterBackgroundNotification
                                           object:nil];

并实现方法

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
    if (getRequest > 0) {
        backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
            [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
            backgroundTaskID = UIBackgroundTaskInvalid;
         }];
    }
}

现在您只有一个正在运行的后台任务,该任务会在您的应用进入后台时自动启动,并且您正在运行的请求会在您的所有请求完成后结束。

另一个改进是将您的网络请求添加到 NSOperationQueue 以避免手动计数并限制并发请求的数量。

【讨论】:

    【解决方案2】:

    无论接下来是什么代码,所做的工作都很简单。该工作未包含在后台任务中。后台任务只是一个 id 和一个状态,它告诉 iOS 框架你是否完成了你的任务。这取决于

    【讨论】:

      猜你喜欢
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      • 1970-01-01
      相关资源
      最近更新 更多