Reputation: 889
I have an HTTP request publisher that when a 401 error is returned, I want to stop execution and display my sign in screen.
Here's part of my code:
cancellable = fetcher.hello(helloRequest: HelloRequest(name: self.name))
.print("fetcher.hello")
.catch { _ in
// TODO: how to handle errors with request?
Just(HelloResponse.placeHolder)
}
.flatMap { response -> AnyPublisher<HelloResponse, Never> in
if response.imageUrl == nil || response.imageUrl == "" {
// If there's no image to download just return the response
return Just(response).eraseToAnyPublisher()
}
else {
// Chain together request and download image
return fetcher.downloadImage(url: response.imageUrl!)
.print("fetcher.hello.downloadImage")
.catch { _ in
// If there was an error downloading the image, replace it with a placeholder
Just(UIImage(named: "placeholder_square")!)
}
.map {
// Add image to response
HelloResponse(message: response.message, visitCount: response.visitCount, imageUrl: response.imageUrl, image: $0)
}
.eraseToAnyPublisher()
}
}
.sink(receiveCompletion: { _ in }, receiveValue: { self.response = $0.self })
So part of the problem is the following flatMap that will download an image if necessary. The output type is AnyPublisher<HelloResponse, Never> (I couldn't think of another way to do that). Right now the catch returns a placeholder model and worked fine. But now I've swallowed the error. I thought maybe Empty() publisher would work but it didn't seem right. I tried Fail() but apparently catch is a Never (makes sense). Thanks!
Upvotes: 3
Views: 9677
Reputation: 889
Using New Dev's suggestion about setFailureType I now have it working. When I originally had the flatMap returning AnyPublisher<HelloWorld, Error> it would not compile because Just is a Never. So I changed the flatMap to Never fail but then I couldn't remove the catch because the previous failure type was Error. Adding setFailureType to the Justs in the flatMap now let me change the flatMap to return Error and I removed the catch.
cancellable = fetcher.hello(helloRequest: HelloRequest(name: self.name))
.print("fetcher.hello")
.flatMap { response -> AnyPublisher<HelloResponse, Error> in
if response.imageUrl == nil || response.imageUrl == "" {
// If there's no image to download just return the response
return Just(response)
.setFailureType(to: Error.self) // This allows us to set a failure type (Just is Never) so that it will match AnyPublisher<HelloResponse, Error>
.eraseToAnyPublisher()
}
else {
// Chain together request and download image
return fetcher.downloadImage(url: response.imageUrl!)
.print("fetcher.hello.downloadImage")
.catch { _ in
// If there was an error downloading the image, replace it with a placeholder
Just(UIImage(named: "placeholder_square")!)
.setFailureType(to: Error.self) // This allows us to set a failure type (Just is Never) so that it will match AnyPublisher<HelloResponse, Error>
}
.map {
// Add image to response
HelloResponse(message: response.message, visitCount: response.visitCount, imageUrl: response.imageUrl, image: $0)
}
.eraseToAnyPublisher()
}
}
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
print("Request error: \(String(describing: error))")
}
}, receiveValue: {
self.response = $0.self
})
}
Upvotes: 4