iOS使用NSURLSessionDataTask进行后台任务

5

我的应用程序中有一个航班搜索功能,获取数据的时间太长了(超过25秒)。如果应用程序进入后台或进入睡眠模式,互联网连接将断开。

我使用苹果示例编写了以下逻辑,使API请求在应用程序进入后台时仍然继续进行,但它没有起作用。

self.session = [self backgroundSession];
self.mutableData = [NSMutableData data];

NSURL *downloadURL = [NSURL URLWithString:@"http://jsonplaceholder.typicode.com/photos"];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
self.dataTask = [self.session dataTaskWithRequest:request];
[self.dataTask resume];

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"];
        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    });
    return session;
}

以下是代理方法:
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
 NSLog(@"response: %@", response.debugDescription);
 NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
    if (completionHandler) {
        completionHandler(disposition);
    }
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    [self.mutableData appendData:data];
}


- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    BLog();

    if (error == nil)
    {
        NSData *data = nil;
        if (self.mutableData) {
            data = [self.mutableData copy];
            self.mutableData = nil;
        }

        NSError* error;
        NSArray* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
        if (!json) {
            NSLog(@"Error parsing JSON: %@", error);
        } else {
            NSLog(@"Data: %@", json);
        }
    }
    else
    {
        NSLog(@"Task: %@ completed with error: %@", task, [error localizedDescription]);
    }

    double progress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive;
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = progress;
    });

    self.dataTask =nil;
}

当应用程序在前台时,一切都正常,但是一旦将应用程序放到后台,就会收到以下错误消息。

完成出错:与后台传输服务失去连接


你尝试过从“Capabilities”选项卡中的目标中添加后台获取功能吗? - Nailer
在 Xcode 的 Capabilities 中启用 Background modes 选项后,可以开启后台获取功能。 - Sanju
是的,我已经这样做了,但是我仍然收到相同的错误信息。 - Jay
1个回答

9
你不能使用数据任务进行后台传输。必须使用下载任务来完成:

下载任务以文件形式检索数据,并支持在应用程序未运行时进行后台下载。

这在苹果的文档中有解释。
还要确保查看他们的后台传输注意事项

对于后台会话,由于实际传输是由单独的进程执行的,并且由于重新启动您的应用程序进程相对较昂贵,因此一些功能不可用,从而导致以下限制...

关键在于它正在单独的进程中运行,无法访问您在内存中保存的数据。它必须通过文件路由。

我在一篇(长篇)博客文章中收集了很多关于iOS后台传输的信息。


谢谢Krumelur!我用下载任务修改了代码,现在它运行得很好。 - Jay
3
在 iOS 8 和 OS X 10.10 之前,后台会话中不支持数据任务。(来自链接文档) - vonovak
这很新鲜。有趣。不确定这会如何运作。感谢指出。 - Krumelur
1
@vonovak 我认为数据任务在iOS 11上仍然不支持。可以通过创建一个数据任务,然后将应用程序放入后台来轻松验证此操作:数据任务将不会运行。不确定为什么苹果在文档中加入了这个令人困惑的语句。我猜苹果的意思是“你不能在iOS 8及之前的后台会话中创建dataTask,但在iOS 9+上,你可以创建dataTask,然后在需要时将其转换为downloadTask”。 - Yi Wang
1
@NSPratik 抱歉回复晚了。也许这可以帮助您以供参考。我已经使用Alamofire.download API实现了后台数据下载。请查看以下链接以获取更多信息。https://github.com/tonyli508/AlamofireDomain#downloading-data-to-a-file - Jay
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接