我有一个在线托管的最新json文件和一个Xcode工作区中的本地json文件。如果获取失败,我想对本地存储的文件进行解码:MyError.fetchError
,例如没有互联网连接。这就是管道:
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()
}
如何做到这一点?
.mapError
是错误的运算符,因为它只考虑Error
分支。
fetchURL
显然返回Data
,因此在解码数据之前,必须用本地数据替换获取错误。
在.decode...
行之前插入
.replaceError(with: try! Data(contentsOf: Bundle.main.url(forResource: "local", withExtension: "json")!))
并删除CCD_ 7运算符。
local.json
表示捆绑包中本地文件的文件名。
我可以提出一种替代但类似的方法来下载数据并处理错误,使用为iOS 15引入的async
功能。
创建一个异步读取数据的函数,如果连接正常,则从服务器返回数据,否则,如果发现问题,则返回本地JSON:
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
}
解码返回的数据:
// 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)")
}