【问题标题】:How to get Error from network request using RxSwift如何使用 RxSwift 从网络请求中获取错误
【发布时间】:2021-07-26 02:08:56
【问题描述】:

我有一个返回 Observable Result 的网络请求,我只想将错误消息作为字符串捕获,以便可以将错误消息与另一条错误消息合并。我尝试使用结果中的 map 仅映射出错误,但我无法弄清楚如何正确捕获错误。

这是我的网络管理员

class NetworkManager {
    private let baseURL = "https://api.github.com/"
    
    func getFollowers(with username: String, page: Int) -> Observable<Result<[Follower], GFError>> {
        let endpoint = baseURL + "users/\(username)/followers?per_page=100&page=\(page)"
        let url = URL(string: endpoint)!
        
        return Observable.create { (observer) -> Disposable in
            let task = URLSession.shared.dataTask(with: url) { data, response, error in
                if let _ = error {
                    observer.onNext(.failure(.unableToComplete))
                    return
                }
                
                guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                    
                    observer.onNext(.failure(.invalidResponse))
                    return
                }
                
                guard let data = data else {
                    observer.onNext(.failure(.invalidData))
                    return
                }
                
                do {
                    let decoder                     = JSONDecoder()
                    decoder.keyDecodingStrategy     = .convertFromSnakeCase
                    decoder.dateDecodingStrategy    = .iso8601
                    
                    let results = try decoder.decode([Follower].self, from: data)
                    observer.onNext(.success(results))
                    observer.onCompleted()
                } catch {
                    observer.onNext(.failure(.invalidData))
                }
            }
            task.resume()
            return Disposables.create {
                task.cancel()
            }
        }
    }

这是我的视图模型

protocol ViewModelType {
    associatedtype Input
    associatedtype Output
    
    func transform(input: Input) -> Output
}

class SearchViewModel: ViewModelType {
    
    // MARK: Properties    
    let manager: NetworkManager
            
    // MARK: Binding
    struct Input {
        let searchText: Observable<String>
        let validate: Observable<Void>
    }
    
    struct Output {
        let followers: Driver<Result<[FollowerViewModel], GFError>>
        let errorMessage: Driver<String>
    }
    
    init(manager: NetworkManager) {
        self.manager = manager
    }
    
    func transform(input: Input) -> Output {
        let followers = input.validate
            .withLatestFrom(input.searchText)
            .filter { !$0.isEmpty }
            .flatMapLatest { query in
                return self.manager.getFollowers(with: query, page: 1)
            }.asDriver { error in
                return Driver.just(.failure(error as! GFError))
            }
        
        let missingName = input.validate
            .withLatestFrom(input.searchText)
            .compactMap { $0.isEmpty ? "Please enter a username. We need to know who to look for" : nil }
            .asDriver(onErrorJustReturn: "")
        
        let errorMessage = followers
        
        let followerVM = followers.map { $0.map { $0.map { FollowerViewModel(follower: $0) }}}
        
        return Output(followers: followerVM, errorMessage: errorMessage)
    }
}

【问题讨论】:

    标签: ios swift mvvm rx-swift


    【解决方案1】:

    您的视图模型非常强大,只有一些小错误。您的网络请求返回 Observable Result 的事实意味着您需要使用紧凑映射和 case let 来提取值。有一些库可以让这更容易。一种叫做 RxEnumKit。

    class SearchViewModel {
    
        // MARK: Properties
        let manager: NetworkManager
    
        // MARK: Binding
        struct Input {
            let searchText: Observable<String>
            let validate: Observable<Void>
        }
    
        struct Output {
            let followers: Driver<[FollowerViewModel]> // note, this should not return a Driver-result.
            let errorMessage: Driver<String>
        }
    
        init(manager: NetworkManager) {
            self.manager = manager
        }
    
        func transform(input: Input) -> Output {
            let followers = input.validate
                .withLatestFrom(input.searchText)
                .filter { !$0.isEmpty }
                .flatMapLatest { query in
                    return self.manager.getFollowers(with: query, page: 1)
                }
    
            let missingName = input.validate
                .withLatestFrom(input.searchText)
                .compactMap { $0.isEmpty ? "Please enter a username. We need to know who to look for" : nil }
    
            // the below extracts the error string from the followers observable and merges it with the missingName observable to make the errorMessage observable.
            let errorMessage = Observable.merge(
                missingName,
                followers.compactMap { (result) -> String? in
                    guard case let .failure(error) = result else { return nil }
                    return error.localizedDescription
                }
            )
            .asDriver(onErrorJustReturn: "")
    
            // use the same thing here to pull the followers out of the Result.
            let followerVM = followers.compactMap { (result) -> [FollowerViewModel]? in
                guard case let .success(followers) = result else { return nil }
                return followers.map { FollowerViewModel(follower: $0) }
            }
            .asDriver(onErrorJustReturn: [])
    
    
            return Output(followers: followerVM, errorMessage: errorMessage)
        }
    }
    

    【讨论】:

    • 再次感谢丹尼尔,你上次帮了我很多忙。现在再次帮助我,你看起来像一个 RxSwift 品牌大使哈哈哈:D。顺便说一句,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多