«Недопустимый аргумент» при попытке использовать фоновый URLSession для задачи загрузки - PullRequest
1 голос
/ 11 марта 2020

Я работаю над приложением, которое требует загрузки определенного количества файлов для работы в автономном режиме. Очевидно, что задачи загрузки предпочтительнее выполнять с приложением в фоновом режиме. Я реализовал URLSession с фоновой конфигурацией, следуя документации Apple, доступной здесь: https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background. Я также следовал учебному пособию по raywenderlich: https://www.raywenderlich.com/3244963-urlsession-tutorial-getting-started.

По сути, то, что я сделал, выглядит так (я сделал свой класс синглтоном, но у меня тоже есть такая же проблема) way):

public final class DownloadService: NSObject {
    static let shared = DownloadService()

    static let identifier = "downloadService"

    private var urlSession: URLSession!

    var backgroundCompletionHandler: (() -> Void)? // This is attributed in the handleEventsForBackgroundURLSession delegate method in the AppDelegate

    private override init() {
        super.init()

        let config = URLSessionConfiguration.background(withIdentifier: DownloadService.identifier)
        config.isDiscretionary = true
        urlSession = URLSession(configuration: config, delegate: self, delegateQueue: nil)
    }
}

extension DownloadService: URLSessionDelegate {
    // Delegate method called when the background session is finished.
    public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        DispatchQueue.main.async {
            guard let completionHandler = self.backgroundCompletionHandler else {
                    Logger.fault("No completion for bg session", category: .network)
                    return
            }
            Logger.log("Complete background session", category: .network)
            // This must be executed on the main thread
            // Executes things such as updating the app preview in recent apps view
            completionHandler()
        }
    }
}

extension DownloadService: URLSessionDownloadDelegate {
    // Delegate method called when a download task is finished
    public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // Perform
        guard let sourceUrl = downloadTask.originalRequest?.url else {
            return
        }
        Logger.log("Received file: %@", sourceUrl.lastPathComponent, category:.network)
        // Check and save file
        saveFile(originalFileURL: sourceUrl, downloadedTo: location)
    }
}

И я начинаю загрузку, используя:

/// Download file using a previously created URLSession.
/// - parameter filename: Name of the file.
/// - parameter baseURL: URL where the files are located.
/// - parameter size: Expected filesize in Bytes.
private func download(file filename: String, from baseURL: String, size: Int64) {
    guard let url = URL(string: baseURL)?.appendingPathComponent(filename) else { return }
    let task = urlSession.downloadTask(with: url)
    task.countOfBytesClientExpectsToSend = 0
    task.countOfBytesClientExpectsToReceive = size
    task.resume()
}

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

Task <46648342-7D13-4D1F-96A1-FDAE4C1F8475>.<362> finished with error [22] Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument"

Я попытался немного поиграть с URLSessionConfiguration, в частности с параметром isDiscretionary , который по умолчанию имеет значение false, и кажется, что установка его в true, как указано в документации Apple, даже блокирует загрузку от продолжения работы с приложением на переднем плане, что приводит к той же ошибке «Неверный аргумент». Интересно, имеет ли этот параметр какое-либо отношение к моей проблеме, или есть что-то, что я неправильно понял? Приведенный выше пример для raywenderlich также работает аналогичным образом: использование isDiscretionary, похоже, приводит к сбою загрузки каждый раз.

Я использую Xcode 11.3.1 с Swift 5 и ориентирован на iOS13.

Позвольте мне узнайте, нужна ли какая-либо другая информация, и спасибо за вашу помощь!

1 Ответ

0 голосов
/ 12 марта 2020

Итак, я пытался сделать это с помощью симулятора. Либо путем запуска из Xcode с отладчиком, либо путем установки приложения в симулятор (без отладчика, поскольку это влияет на жизненный цикл приложения).

Я попытался запустить его на реальном устройстве (iPad), и есть никаких признаков этой ошибки вообще! Настройка isDiscretionary, кажется, работает как задумано, поэтому я не уверен, что этот параметр вызывал проблему на симуляторе.

...