Как связать данные из viewModel с помощью rxSwift и Moya? - PullRequest
1 голос
/ 20 января 2020

Я пытаюсь создать приложение, чтобы получать новости от API, и я использую Moya, RxSwift и MVVM. Это моя ViewModel:

import Foundation
import RxSwift
import RxCocoa

public enum NewsListError {
    case internetError(String)
    case serverMessage(String)
}

enum ViewModelState {
    case success
    case failure
}

protocol NewsListViewModelInput {
    func viewDidLoad()
    func didLoadNextPage()
}

protocol MoviesListViewModelOutput {
    var newsList: PublishSubject<NewsList> { get }
    var error: PublishSubject<String> { get }
    var loading: PublishSubject<Bool> { get }
    var isEmpty: PublishSubject<Bool> { get }
}

protocol NewsListViewModel: NewsListViewModelInput, MoviesListViewModelOutput {}

class DefaultNewsListViewModel: NewsListViewModel{

    func viewDidLoad() {

    }

    func didLoadNextPage() {

    }


    private(set) var currentPage: Int = 0
    private var totalPageCount: Int = 1

    var hasMorePages: Bool {
        return currentPage < totalPageCount
    }
    var nextPage: Int {
        guard hasMorePages else { return currentPage }
        return currentPage + 1
    }

    private var newsLoadTask: Cancellable? { willSet { newsLoadTask?.cancel() } }

    private let disposable = DisposeBag()

    // MARK: - OUTPUT
    let newsList: PublishSubject<NewsList> = PublishSubject()
    let error: PublishSubject<String> = PublishSubject()
    let loading: PublishSubject<Bool> = PublishSubject()
    let isEmpty: PublishSubject<Bool> = PublishSubject()

    func getNewsList() -> Void{
        print("sono dentro il viewModel!")
        NewsDataService.shared.getNewsList()
            .subscribe { event in
                switch event {
                case .next(let progressResponse):
                    if progressResponse.response != nil {
                        do{
                            let json = try progressResponse.response?.map(NewsList.self)
                            print(json!)
                            self.newsList.onNext(json!)
                        }
                        catch _ {
                            print("error try")
                        }
                    } else {
                        print("Progress: \(progressResponse.progress)")
                    }
                case .error( _): break
                // handle the error
                default:
                    break
                }
        }
    }

}

Это мой ViewController, где xCode выдает мне следующую ошибку при попытке привязки к tableNews:

Expression type 'Reactive<_>' is ambiguous without more context
import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {

    @IBOutlet weak var tableNews: UITableView!

    let viewModel = DefaultNewsListViewModel()

    var disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    private func setupBindings() {

        viewModel.newsList.bind(to: tableNews.rx.items(cellIdentifier: "Cell")) {
            (index, repository: NewsList, cell) in
            cell.textLabel?.text = repository.name
            cell.detailTextLabel?.text = repository.url
        }
        .disposed(by: disposeBag)
    }
}

Это служба которые получают данные из API:


import Moya
import RxSwift
struct NewsDataService {
    static let shared = NewsDataService()

    private let disposable = DisposeBag()

    private init() {}

    fileprivate let newsListProvider = MoyaProvider<NewsService>()

    func getNewsList() -> Observable<ProgressResponse> {
        self.newsListProvider.rx.requestWithProgress(.readNewsList)
        }
    }

Я новичок в rxSwift, я следовал за некоторыми документами, но я хотел бы знать, правильно ли я подхожу. Еще один момент, который я хотел бы знать, - как правильно связать мой tableView с viewModel. Спасибо за поддержку.

1 Ответ

0 голосов
/ 23 января 2020

Как отметил @FabioFelici в комментариях, UITableView.rx.items(cellIdentifier:) ожидает привязки к Observable, который содержит массив объектов, но ваш NewsListViewModel.newsList является Observable<NewsList>.

Это означает, что вы либо имеете извлечь массив из NewsList (при условии, что он есть) через карту. Как и в newsList.map { $0.items }.bind(to: ...

Кроме того, ваш MoviesListViewModelOutput не должен быть полон субъектов, скорее, он должен содержать наблюдаемые. И я не стал бы беспокоиться о протоколах, strut s в порядке.

Кроме того, ваша модель представления все еще очень обязательна, не совсем в стиле Rx. Хорошо построенная модель представления Rx не содержит функций, которые вызываются неоднократно. У него просто есть конструктор (или он сам по себе является единственной функцией). Вы создаете его, привязываете к нему, и тогда все готово.

...