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.