Swift Combine-如何引发错误并停止执行

问题描述

我有一个HTTP请求发布者,当返回401错误时,我想停止执行并显示登录屏幕。

这是我的代码的一部分:

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 })

因此,一部分问题是下面的flatMap,如果需要,它将下载图像。输出类型为AnyPublisher (我想不出另一种方法)。现在,该捕获返回一个占位符模型,并且运行良好。但是现在我已经吞噬了这个错误。我以为Empty()发行商可以工作,但似乎不正确。我尝试了Fail(),但显然catch是一个Never(有意义)。谢谢!

解决方法

使用New Dev关于setFailureType的建议,现在我可以使用它了。当我最初让flatMap返回AnyPublisher 时,它将无法编译,因为Just是一个Never。因此,我将flatMap更改为“永不失败”,但是由于先前的失败类型为“错误”,所以我无法删除捕获。现在,将setFailureType添加到flatMap的Justs中,让我将flatMap更改为返回Error,并删除了捕获。

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
            })
    }