为什么我的 Combine httpMethod post 请求不起作用?

Why is my Combine httpMethod post request not working?

我正在尝试使用 Combine 执行 POST 请求。在执行我之前使用的 http 请求时,我的 Credentials 对象返回状态代码 200,一切正常。但是当我尝试使用 Combine 框架时,它只是 returns 一个错误。

finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled"

如何解决此问题以使我的 Combine POST 请求按预期工作?

我的 Combine 请求不起作用,需要修复:

func demoLogin() -> AnyPublisher<Credentials, Error> {
  let url = URL(string: "https://web-api/auth/create-demo-account")!

  var urlRequest = URLRequest(url: url)
  urlRequest.httpMethod = "POST"

  return URLSession.shared
    .dataTaskPublisher(for: urlRequest)
    .receive(on: DispatchQueue.main)
    .map(\.data)
    .decode(
      type: Credentials.self,
      decoder: JSONDecoder())
    .eraseToAnyPublisher()
}

所以这是我下沉价值的地方:

final class OnboardingViewModel: ObservableObject {

  private var subscriptions = Set<AnyCancellable>()

  func demoLogin() {
    AuthRequest.shared.demoLogin()
      .sink(
        receiveCompletion: { print([=13=]) },
        receiveValue: {
          print("Receive value:\nLogin: \([=13=].login)\nToken: \([=13=].token)") })
      .store(in: &subscriptions)
  }
}

这是按钮请求调用的 SwiftUI 视图:

struct CredentialsButtons: View {

  @ObservedObject var viewModel = OnboardingViewModel()

  var body: some View {
    VStack {
      Button(action: { self.viewModel.demoLogin() }) {
        Text("Try demo")
          .font(.subheadline)
          .fontWeight(.medium)
          .foregroundColor(.blue)
      }
    }
  }
}

我的请求正常工作:

  func demoLogin(completion: @escaping (NetworkResult<Credentials>) -> Void) {
    let url = URL(string: "https://web-api/auth/create-demo-account")!

    var urlRequest = URLRequest(url: url)
    urlRequest.httpMethod = "POST"

    let dataTask = authSession.dataTask(with: urlRequest) { data, response, error in
      guard let httpResponse = response as? HTTPURLResponse,
        httpResponse.statusCode == 200,
        let jsonData = data else {
          completion(.failure)
          return
      }
      do {
        let credentials = try JSONDecoder().decode(Credentials.self, from: jsonData)
        completion(.success(credentials))
      }
      catch {
        completion(.failure)
      }
    }
    dataTask.resume()
  }

这不是有效的 URL。如下所示将印刷品插入您的出版商,以便您可以看到错误:

func demoLogin() -> AnyPublisher<Credentials, Error> {
  let url = URL(string: "https://web-api/auth/create-demo-account")!

  var urlRequest = URLRequest(url: url)
  urlRequest.httpMethod = "POST"

  return URLSession.shared
    .dataTaskPublisher(for: urlRequest)
    .receive(on: DispatchQueue.main)
    .map(\.data)
    .print()
    .decode(
      type: Credentials.self,
      decoder: JSONDecoder())
    .eraseToAnyPublisher()
}

一旦获得 return 有效数据,您就可以在解码后移动打印件以报告和解码错误。

网络调用按预期工作。在我调用 demoLogin() ViewModel 方法的按钮中找到了导致此错误的代码。问题是我无法在调用 ViewModel 网络的同时调用 @State 变量。

发送错误的按钮:

Button(action: {
  withAnimation {
    self.viewModel.demoLogin()
    self.isLoggedIn.toggle()
    self.enterDemoMode.toggle() }
}) {
  Text("Try demo")
    .font(.subheadline)
    .fontWeight(.medium)
    .foregroundColor(.blue)
}

通过将 SwiftUI 视图的 @State 变量替换为我的 ViewModel 中的 @Published 变量并在 demoLogin() 中而不是在 SwiftUI 视图按钮中调用它们来修复错误。

Button(action: {
  withAnimation {
    self.viewModel.demoLogin() } // Fixed
}) {
  Text("Try demo")
    .font(.subheadline)
    .fontWeight(.medium)
    .foregroundColor(.blue)
}