ios - 带有未在后台调用的请求 block 的 URLSession.datatask

标签 ios swift xcode xcode8 nsurlsession

URLSession 数据任务 block 在应用程序处于后台时未调用,它停留在 dataTask 请求。
当我打开应用程序时, block 被调用。顺便说一下,我正在使用 https 请求。
这是我的代码:

    let request = NSMutableURLRequest(url: URL(string: url as String)!,

                                      cachePolicy: .reloadIgnoringCacheData,

                                      timeoutInterval:20)

    request.httpMethod = method as String

    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

    let session = URLSession.shared

    let data = params.data(using: String.Encoding.utf8.rawValue)

    request.httpBody = data

    session.dataTask(with: request as URLRequest,completionHandler:

        {(data, response, error) -> Void in

         if error == nil

            {

                do {

                    let result = try JSONSerialization.jsonObject(with: data!, options:

                        JSONSerialization.ReadingOptions.mutableContainers)

                    print(result)

                     completionHandler(result as AnyObject?,nil)

                }

                catch let JSONError as NSError{

                    completionHandler(nil,JSONError.localizedDescription as NSString?)

                }

            }

            else{

                completionHandler(nil,error!.localizedDescription as NSString?)                    

            }                

    }).resume()

当应用程序处于事件状态时完美运行。我的代码有什么问题吗?请指点我

最佳答案

如果您希望在您的应用程序不再处于前台后继续下载,您必须使用后台 session 。 Downloading Files in Background 中概述了后台 session 的基本限制。 , 本质上是:

  1. 使用基于委托(delegate)的 URLSession 和后台 URLSessionConfiguration

  2. 仅使用上传和下载任务,没有完成处理程序。

  3. 在 iOS 中,实现 application(_:handleEventsForBackgroundURLSession:completionHandler:)应用程序委托(delegate),保存完成处理程序并启动后台 session 。

    实现urlSessionDidFinishEvents(forBackgroundURLSession:)在您的 URLSessionDelegate 中,调用保存的完成处理程序让操作系统知道您已完成后台请求完成处理。

所以,把它们放在一起:

func startRequest(for urlString: String, method: String, parameters: String) {
    let url = URL(string: urlString)!
    var request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: 20)
    request.httpMethod = method
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.httpBody = parameters.data(using: .utf8)
    BackgroundSession.shared.start(request)
}

在哪里

class BackgroundSession: NSObject {
    static let shared = BackgroundSession()
    
    static let identifier = "com.domain.app.bg"
    
    private var session: URLSession!

    #if !os(macOS)
    var savedCompletionHandler: (() -> Void)?
    #endif
    
    private override init() {
        super.init()
        
        let configuration = URLSessionConfiguration.background(withIdentifier: BackgroundSession.identifier)
        session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }
    
    func start(_ request: URLRequest) {
        session.downloadTask(with: request).resume()
    }
}

extension BackgroundSession: URLSessionDelegate {
    #if !os(macOS)
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        DispatchQueue.main.async {
            self.savedCompletionHandler?()
            self.savedCompletionHandler = nil
        }
    }
    #endif
}

extension BackgroundSession: URLSessionTaskDelegate {
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            // handle failure here
            print("\(error.localizedDescription)")
        }
    }
}

extension BackgroundSession: URLSessionDownloadDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        do {
            let data = try Data(contentsOf: location)
            let json = try JSONSerialization.jsonObject(with: data)
            
            print("\(json)")
            // do something with json
        } catch {
            print("\(error.localizedDescription)")
        }
    }
}

而 iOS 应用程序委托(delegate)会执行以下操作:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    BackgroundSession.shared.savedCompletionHandler = completionHandler
}

关于ios - 带有未在后台调用的请求 block 的 URLSession.datatask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44128358/

相关文章:

ios - 无法快速生成 CustomTableViewCell cellIdentifier 扩展?

ios - UIButton 和 UIScrollView - 按下按钮时滚动

ios - 如何访问 UICollectionView 中选定单元格的索引

xcode - 白色背景的应用程序图标仅在 iOS 上显示为黑色

ios - 如何在 Swift 中重用字体?

ios - UICollectionView 仅在 Scroll 上加载图像

ios - 异步加载后更新 UITableView 中的数据

ios - 导入唯一对象时 CoreStore 映射关系

DatePicker 配置 swift

c++ - 在 iPhone/iPad 项目中 #import C++ 头文件时出现问题