使用多个beginBackgroundTaskWithExpirationHandler调用

时间:2012-03-11 22:15:00

标签: iphone

我想在此处关注此前发布的帖子: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,因为你应该使用endBackgroundTask:call来平衡beginBackgroundTaskWithExpirationHandler。如果是这样,我怎么做,因为我的getRequest当前没有该基础设施?我是否需要50个ivars才能使connectionDidFinishLoading方法看到对getRequest的50个初始调用?感谢。

2 个答案:

答案 0 :(得分:5)

正如您所说,您需要通过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,以避免手动计数并限制并发请求的数量。

答案 1 :(得分:1)

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