Использование Swift и Combine wait для получения результатов от вызова веб-службы и выполнения следующего вызова - PullRequest
0 голосов
/ 21 сентября 2019

Чтобы сделать некоторые другие вызовы, нужен токен доступа, поэтому идея состоит в том, чтобы получить токен доступа и, как только он будет получен, затем использовать его для следующего вызова.

Вот фактический вызов, но создание запроса игнорируется:

@available(iOS 13.0, *)
func postToken(session: URLSession = URLSession.shared) throws -> URLSession.DataTaskPublisher {
    let request = try buildTokenRequest()
    return session.dataTaskPublisher(for: request)
}

@available(iOS 13.0, *)
public func fetchToken() -> AnyPublisher<AccessToken, Error> {
    return try! postToken()
        .tryMap{ try self.validate($0.data, $0.response) }
            .decode(type: AccessToken.self, decoder: JSONDecoder())
            .eraseToAnyPublisher()
}

Проверка довольно проста, но может быть полезна:

@available(iOS 13.0, *)
func validate(_ data: Data, _ response: URLResponse) throws -> Data {
    guard let httpResponse = response as? HTTPURLResponse else {
        throw APIError.invalidResponse
    }
    guard (200..<300).contains(httpResponse.statusCode) else {
        throw APIError.statusCode(httpResponse.statusCode)
    }
    return data
}

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

@available(iOS 13.0, *)
func testRetrieveToken() {
    let cancellableLogin = AccessTokenService().fetchToken()
    .sink(receiveCompletion: { (completion) in
        switch completion {
        case .failure(let error):
            print(error)
        case .finished:
            print("BEARER TOKEN")
        }
    }, receiveValue: { response in
        print(response)
        XCTAssertNotNil(response)
    })
}

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

Это результаты моего выполнения:

Test Case '-[AccessTokenServiceTests.AccessTokenServiceTests testRetrieveToken]' started.
Test Case '-[AccessTokenServiceTests.AccessTokenServiceTests testRetrieveToken]' passed (0.004 seconds).

Это должно было занять около 1 секунды, если бы он ожидал генерации токена.

** Обновление **

Я изменил тест следующим образом, так что я думаю, что решение можетбыть может использовать PassThroughSubject возможно.Это может потребовать времени, поэтому я вызываю его при запуске приложения, затем оно должно вернуться до того, как будет вызван первый веб-сервис, или я жду, пока получу факт, что оно установлено.

    let expectation = self.expectation(description: "Scaling")
    let cancellableLogin = AccessTokenService().fetchToken()
    .sink(receiveCompletion: { (completion) in
        switch completion {
        case .failure(let error):
            print(error)
            expectation.fulfill()
            XCTFail()
        case .finished:
            print("BEARER TOKEN")
        }
    }, receiveValue: { response in
        print(response)
        XCTAssertNotNil(response)
        XCTAssertEqual(response.token_type, "Bearer")
        expectation.fulfill()
    })
    waitForExpectations(timeout: 60, handler: nil)
...