Метод заканчивается до получения данных от Combine Future Publisher - PullRequest
0 голосов
/ 09 марта 2020

У меня есть такой код:

import Cocoa
import Combine

func prepareURLRequest(for url: URL) -> URLRequest {
    let request = URLRequest(url: url)
    var token = "token"

    print("start value: \(token)")

    let subscription = Token()
    subscription.getToken()
        .sink(receiveCompletion: { _ in
        print("subscription completed")
    }, receiveValue: { value in
        token = value
        print("value received: \(token)")
    })

    print("new value: \(token)")

    // attach received token to request
    return request
}


class Token {
    let token = PassthroughSubject<String,Never>()

    func verify() -> Bool {
        // TODO: Token verification logic
        Bool.random()
    }

    func getToken() -> AnyPublisher<String,Never> {
        return Future<String, Never> { promise in
            if self.verify() {
                let url = URLRequest(url: URL(string: "http://avatars.io/twitter/twostraws")!)
                URLSession.shared.dataTask(with: url) { data, response, error in
                    print("Data Task started")
                    if let error = error {
                        print("error \(error)")

                    }
                    guard let data = data else {
                        preconditionFailure("data error")
                    }
                    guard let response = response as? HTTPURLResponse else {
                        preconditionFailure("response error")
                    }

                    print("data task received response with code: \(response.statusCode)")
                    promise(.success("\(response.statusCode)"))
                }.resume()
            } else {
                print("keychain path")
                sleep(2)
                promise(.success("kwychain path success"))
            }
        }.eraseToAnyPublisher()
    }
}

let url = URL(string: "http://avatars.io/twitter/twostraws")!
let request = prepareURLRequest(for: url)

код должен прикрепить полученный токен к объекту подготовленного запроса Теперь только verify -> false path возвращает данные в требуемом порядке. Когда я пытаюсь verify -> true данные пути попадают после того, как prepareURLRequest заканчивает свою жизнь.

Как это исправить, чтобы оба пути приводили к правильному порядку (и токен обновлялся до завершения метода prepareURLRequest?

1 Ответ

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

Проблема в том, что вы не заключили в будущее Отложенное. Ваш код написан в ожидании, что вызовы API не будут выполняться до тех пор, пока не будет запрошен запрос, но это не совсем так, как работает Future.

Как только Future создан, он вызывает его базовый асинхронный c API вызов для представления - и вы используете вышеуказанный объект PassthroughSubject, это означает, что он уже сделан, это вызов к тому времени, когда у вас есть подписчик, запрашивающий данные. Лучший способ решить эту проблему - обернуть Future в Deferred издателе, который ждет его создания, пока подписка не запросит данные. Страница будущего использования Использование Combine , а также дополнительная информация о том, как работает Future и что с ним делают другие операторы.

...