I have an up-to-date json file hosted online and a local json file in my Xcode workspace. I would like to proceeed to decode a locally stored file if fetching failed: MyError.fetchError
e.g. for no internet connection. This is the pipeline:
func fetchAndDecode<T: Decodable>(url: URL) -> AnyPublisher<T, MyError> {
fetchURL(url: url)
.decode(type: T.self, decoder: JSONDecoder())
.mapError { error in
if let error = error as? DecodingError {
return MyError.parsingError
} else {
return MyError.fetchError //here somehow proceed to parse local json file
}
}
.eraseToAnyPublisher()
}
How to achieve this ?
CodePudding user response:
.mapError
is the wrong operator because it considers only the Error
branch.
fetchURL
returns obviously Data
, so before decoding the data you have to replace the fetch error with the local data.
Before the .decode...
line insert
.replaceError(with: try! Data(contentsOf: Bundle.main.url(forResource: "local", withExtension: "json")!))
and delete the .mapError
operator.
local.json
represents the file name of the local file in the bundle.
CodePudding user response:
I can propose an alternate but similar method to download the data and handle the error, using the async
functions introduced for iOS 15.
Create a function that reads the data asynchronously and returns the data from the server if the connection worked, otherwise it will return the local JSON if a problem was found:
func getData(fromURL url: URL) async -> Data {
let request = URLRequest(url: url)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("HTTP response: \(response.debugDescription)")
// Found an issue: return the local JSON
return localJSON
}
// If everything is OK, return the data from the server
return data
}
Decode the data returned:
// Use the code below in an asynchronous environment -
// either an async function or inside a Task { } closure
let data = await getData(fromURL: url)
do {
let decoded = try JSONDecoder().decode(T.self, from: data)
print("Decoded JSON: \(decoded)")
return decoded
} catch {
print("Error decoding JSON: \(error), \(error.localizedDescription)")
}