Как обеспечить стабильную связь с Alamofire на фоне iOS - PullRequest
0 голосов
/ 25 октября 2019

Из моих часов я отправляю команды в мое приложение для iOS. Непонятно почему, но если приложение работает в фоновом режиме, я вижу некоторые ошибки:

Error Domain=NSURLErrorDomain Code=-997 "Lost connection to background transfer service"

Can't end BackgroundTask: no background task exists with identifier 383 (0x17f), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.

Я уже пытался изменить свойКонфигурация в фоновом режиме, иметь правильный идентификатор для моей конфигурации. Статическая или Ленивая реализация моего SessionManager. Подсчет deinit в процессе.

Диспетчер сетевых сеансов

static var sessionManager: SessionManager = {
        let configuration = URLSessionConfiguration.background(withIdentifier: UUID().uuidString + ".WatchOS_Background")
        configuration.httpShouldSetCookies = false
        configuration.httpMaximumConnectionsPerHost = 4
        configuration.timeoutIntervalForRequest = 50
        configuration.networkServiceType = .background
        configuration.isDiscretionary = false
        configuration.shouldUseExtendedBackgroundIdleMode = true
        if #available(iOS 13.0, *) {
            configuration.allowsExpensiveNetworkAccess = true
            configuration.allowsConstrainedNetworkAccess = true
        }

        let sessionManager = Alamofire.SessionManager(configuration: configuration)
        sessionManager.delegate.sessionDidBecomeInvalidWithError = { _, error in
            if let error = error {
                print(error)
            }
        }
        sessionManager.delegate.taskDidComplete = { _, task, error in
            if let error = error {
                print(error)
            }
        }
        return sessionManager
    }()

Пример запроса

func getListFromServer(completion: @escaping (ServiceResponse<[Model1]>) -> Void) {
        let header: HTTPHeaders = ["User-Agent": UserAgentHelper.fullUserAgentString]
        request("/api/1/XXXX", method: .get, parameters: nil, encoding: nil, headers: header).responseData { [weak self] response in
            guard let strongSelf = self else { return }
            completion(strongSelf.completionResponse(response))
        }
    }

Метод запроса

@discardableResult private func request(
        _ path: String,
        method: HTTPMethod,
        parameters: Parameters? = nil,
        encoding: ParameterEncoding? = nil,
        headers: HTTPHeaders? = nil)
        -> DataRequest {
            let userEncoding = encoding ?? self.defaultEncoding
            let task = beginBackgroundTask()
            let dataRequest = NetworkService.sessionManager.request("\(API)\(path)",
                method: method,
                parameters: parameters,
                encoding: userEncoding,
                headers: headers)

            dataRequest.validate()

            self.endBackgroundTask(taskID: task)
            return dataRequest
    }

Начало и конецфоновое задание

func beginBackgroundTask() -> UIBackgroundTaskIdentifier {
      return UIApplication.shared.beginBackgroundTask(withName: "Background_API", expirationHandler: {})
}

func endBackgroundTask(taskID: UIBackgroundTaskIdentifier) {
      UIApplication.shared.endBackgroundTask(taskID)
}

Я надеюсь получить правильную реализацию из вашего жизненного цикла стабильного запроса.

Большое спасибо за вашу помощь и заранее извиняюсь за отсутствие технических терминов.

1 Ответ

1 голос
/ 25 октября 2019

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

let task = UIApplication.shared.beginBackgroundTask(withName: "Background_API") {
    UIApplication.shared.endBackgroundTask(task)
}

Я предлагаю вам прочитать подробнее здесь , где инженер Apple DTS подробно изложил требования и крайние случаи фоновой задачиобработка.

Кроме того, Alamofire не поддерживает фоновые сеансы. Возможно, лучше всего использовать сеанс переднего плана с обработкой фоновых задач. После деинициализации Alamofire SessionManager все запущенные им запросы будут отменены, даже для фоновых сессий.

Наконец, вызов validate() в обработчике ответов Alamofire недопустим. Вы должны вызывать его по запросу до добавления обработчика ответа, поскольку он проверяет ответ до вызова обработчиков. Если вы вызываете его позже, он не сможет передать выдаваемую ошибку в ваш обработчик ответа.

...