Запрос Alamofire в приложении перешел в фоновый режим. Связь потеряна

#swift #xcode

Вопрос:

Когда приложение переходит в фоновый режим, оно хочет сделать один запрос, к сожалению, оно получает сообщение об ошибке:

 sessionTaskFailed (error: Error Domain = NSURLErrorDomain Code = -1005 "The network connection was lost...")
 

Код:

 override func viewDidLoad() {
        super.viewDidLoad()
    notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}


@objc func appMovedToBackground() {

let URL: String = "http://www.test.com/"
AF.request(URL, method: .post, parameters: parameters, headers: headers)
  .responseJSON { [] response in
                                
  switch response.result {
   case .success(let data):
     print(data)
   case .failure(let error):
     print(error)
   }
 }

}
 

Ответ №1:

Похоже, вам следует реализовать фоновую задачу. В документации Apple приведен пример того, как это сделать:

 func sendDataToServer( data : NSData ) {
   // Perform the task on a background queue.
   DispatchQueue.global().async {
      // Request the task assertion and save the ID.
      self.backgroundTaskID = UIApplication.shared.
                 beginBackgroundTask (withName: "Finish Network Tasks") {
         // End the task if time expires.
         UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
         self.backgroundTaskID = UIBackgroundTaskInvalid
      }
            
      // Send the data synchronously.
      self.sendAppDataToServer( data: data)
            
      // End the task assertion.
      UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
      self.backgroundTaskID = UIBackgroundTaskInvalid
   }
}
 

Редактировать

Я не компилировал этот код, но, основываясь на документации Apple, это можно было бы сделать примерно так:

 final class ViewControler: UIViewController {
    
    private var backgroundTaskID: UIBackgroundTaskIdentifier?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if #available(iOS 13.0, *) {
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(willResignActive),
                                                   name: UIScene.willDeactivateNotification,
                                                   object: nil)
        } else {
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(willResignActive),
                                                   name: UIApplication.willResignActiveNotification,
                                                   object: nil)
        }
    }
    
    @objc func willResignActive(_ notification: Notification) {
        // Perform the task on a background queue.
        DispatchQueue.global().async {
            // Request the task assertion and save the ID.
            self.backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Finish Network Tasks") {
                // End the task if time expires.
                UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
                self.backgroundTaskID = .invalid
            }
            
            self.sendRequest()
        }
    }
    
    func sendRequest() {
        let URL: String = "http://www.test.com/"
        AF.request(URL, method: .post, parameters: parameters, headers: headers)
            .responseJSON { [unowned self] response in
                
            // End the task assertion.
            UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
            self.backgroundTaskID = .invalid
            
            switch response.result {
            case .success(let data):
                print(data)
            case .failure(let error):
                print(error)
            }
        }
    }
}
 

В этом коде мы подписываемся на уведомление, когда приложение будет
войдите в фоновый режим и создайте фоновую задачу. В фоновой задаче мы выполняем необходимый запрос. Если этот запрос при закрытии ответа выполняется быстрее, чем за 5 секунд, мы аннулируем нашу фоновую задачу и завершаем работу с ней. Если запрос выполняется дольше 5 секунд, фоновая задача завершается.

Комментарии:

1. Вопрос в том, как это сделать, когда запрос iAF является асинхронным. У меня мало запросов в цикле.

2. @tomtript Я обновил свой ответ