简体   繁体   中英

"Task finished with error [-999]" in SwiftUI

I am trying to make an HTTP GET request using Combine to the https://myLink.com URL (this is a fake URL, the one that I use is a real API link and it works, but I can't post it), but when I call the function I get the following error:

Task <18F5A03A-96DF-4309-B263-B6B0CB275779>.<1> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey= https://myLink.com , NSLocalizedDescription=cancelled, NSErrorFailingURLKey= https://myLink.com }

Here is my code:

import SwiftUI
import Foundation
import Combine

struct ContentView: View {
   var body: some View {
      Button(action: {
         loadPatients()
      })
      {
         Text("Load Patients")
      }
   }
}

//MARK: - Your object to retrieve from JSON
struct Doctor: Codable, Identifiable {
  let id = UUID()
  let patients: [Patients]
}

struct Patients: Codable {
  let id: String
  let name: String
  let phone: String
}

class Network {

  // Handle your request errors
  enum Error: LocalizedError {
    case invalidResponse
    case addressUnreachable(URL)

    var errorDescription: String? {
      switch self {
      case .invalidResponse:
        return "The server responded with garbage."
      case .addressUnreachable(let url):
        return "\(url.absoluteString) is unreachable."
      }
    }
  }

  // Add your url
  let urlRequest = URL(string: "https://coronavirus-med.herokuapp.com/api/v1/doctor/getPatients/bogdand")!

  // Networking on concurrent queue
  let networkQueue = DispatchQueue(label: "Networking",
                                   qos: .default,
                                   attributes: .concurrent)

  // Combine network call (This replace your previous code)
  func downloadPatients() -> AnyPublisher<Doctor, Error> {
    URLSession.shared
      .dataTaskPublisher(for: urlRequest)
      .receive(on: networkQueue)
      .map(\.data)
      .decode(type: Doctor.self, decoder: JSONDecoder())
      .mapError { (error) -> Network.Error in
        switch error {
        case is URLError:
          return Error.addressUnreachable(self.urlRequest)
        default:
          return Error.invalidResponse
        }
    }
    .eraseToAnyPublisher()
  }
}

let networkRequest = Network()

//MARK: - Call this function where you want to make your call
func loadPatients() {
  _ = networkRequest.downloadPatients()
    .sink(
      receiveCompletion: {
        print("Received Completion: \($0)") },
      receiveValue: { doctor in
        // doctor is your response and [0].name is your first patient name
        print(doctor.patients[0].name) }
  )
}

I found another question on StackOverflow addressing this error, but the answer just says what the error means, but not how to solve it. They said that it means that a request is made before another one is finished, but I don't make any requests before this one, I even tried to run this in a new empty project but it still gives me the same error.

I was on iOS 13.2 and Xcode 11.2 and I updated to iOS 13.4 and Xcode 11.4, still the same error.

This is the JSON response:

{
    "code": 200,
    "status": "success",
    "patients": [
        {
            "_id": "5e77c7bbc7cbd30024f3eadb",
            "name": "Bogdan Patient",
            "username": "bogdanp",
            "phone": "0732958473"
        },
        {
            "_id": "5e77c982a2736a0024e895fa",
            "name": "Robert Patient",
            "username": "robertp",
            "phone": "0739284756"
        }
    ]
}

To get the result from network call you need to change your content view in this way:

struct ContentView: View {

    let networkRequest = Network()
    @State var cancelable: AnyCancellable? = nil

    var body: some View {
        Button(action: {
            self.loadPatients()
        })
        {
            Text("Load Patients")
        }
    }

    //MARK: - Call this function where you want to make your call
    func loadPatients() {
       cancelable = networkRequest.downloadPatients()
            .sink(
                receiveCompletion: {
                    print("Received Completion: \($0)") },
                receiveValue: { doctor in
                    // doctor is your response and [0].name is your first patient name
                    print(doctor.patients[0].name) }
        )
    }

}

you should store the network call in AnyCancellable . When using it inside a view, you need to use a @State variable, to make sure it survives after the view body was generated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM