Mam następujący kod MVVM-C + RxSwift.

Problem polega na tym, że TableView nie odbiera żadnych sygnałów. Kiedy ja debuguj wyniki Widzę, że wywołanie API zwraca to, co powinno, tablica objects jest wypełniona obiektami, ale widok tabeli nie pokazuje żadnych wyników. Oto dane wyjściowe konsoli:

2018-11-13 16:12:08.107: searchText -> Event next(qwerty)
Search something: qwerty
2018-11-13 16:12:08.324: viewModel.data -> Event next([])

Czy to może być sam widok tabeli? Może zła niestandardowa konfiguracja komórki?

ViewController.swift:

    tableView = UITableView(frame: self.view.frame)
    tableView.delegate = nil
    tableView.dataSource = nil
    tableView.register(SearchResultCell.self, forCellReuseIdentifier: "SearchResultCell")

    viewModel.data
        .debug("viewModel.data", trimOutput: false)
        .drive(tableView.rx.items(cellIdentifier: "SearchResultCell")) { row, object, cell in

            cell.name.text = object.name
            cell.something.text = object.something
        }
        .disposed(by: disposeBag)

ViewModel.swift:

let disposeBag = DisposeBag()
var searchText = BehaviorRelay(value: "something to search for")

lazy var data: Driver<[Object]> = {
    return self.searchText.asObservable()
        .debug("searchText", trimOutput: false)
        .throttle(0.3, scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .flatMapLatest(searchSomething)
        .asDriver(onErrorJustReturn: [])
}()

func searchSomething(query: String) -> Observable<[Object]> {

    print("Search something: \(query)")

    let provider = MoyaProvider<APIService>()

    var objects = [Object]()

    provider.rx.request(.search(query: query)).subscribe { event in
        switch event {
        case let .success(response):
            do {
                let responseJSON: NSDictionary = try (response.mapJSON() as? NSDictionary)!
                objects = self.parse(json: responseJSON["results"] as Any)

            } catch(let error) {
                print(error)
            }

            break
        case let .error(error):
            print(error)
            break
        }
    }
    .disposed(by: disposeBag)

    let result: Observable<[Object]> = Observable.from(optional: objects)

    return result
}
0
Blackbeard 14 listopad 2018, 11:31

1 odpowiedź

Najlepsza odpowiedź
  • Korzystając z flatMap, nie chcesz tworzyć zagnieżdżonych subskrypcji. Stworzysz Observable, który zwróci oczekiwany wynik, a flatMap zajmie się jego zasubskrybowaniem. W obecnym stanie rzeczy searchSomething zawsze zwróci pustą tablicę, ponieważ Observable.from(optional: objects) zostanie wywołane, zanim żądanie będzie miało szansę się zakończyć.
  • Od wersji 10.0 Moya dostawca anuluje utworzone żądania po cofnięciu alokacji. Tutaj zostanie on cofnięty, gdy wykonanie zakończy się searchSomething, stąd żądanie sieciowe nie będzie miało czasu na zakończenie. Przeniesienie deklaracji dostawcy na poziom modelu widoku rozwiązuje ten problem.

Oto searchSomething(query: String) -> Observable<[Object]> przepisany.

let provider = MoyaProvider<APIService>()

func searchSomething(query: String) -> Observable<[Object]> {

    print("Search something: \(query)")

    return provider.rx.request(.search(query: query)).map { (response) -> [Object] in
        let responseJSON: NSDictionary = try (response.mapJSON() as? NSDictionary)!

        return self.parse(json: responseJSON["results"] as Any)
    }
}

Zamiast wykonywać transformację w subskrypcji, robi się to w map, które będzie wywoływane dla każdego zdarzenia next, przekazując wartość związaną ze zdarzeniem.

1
tomahh 14 listopad 2018, 13:34