Плоская карта RXSwift, которая возвращается из обработчика асинхронного завершения

Я пытаюсь создать searchBar, который ищет адреса через MKLocalSearch с запросом и с использованием RXSwift и привязкой к RXCocoa

Пока что я выполнил следующие 1. фильтры и устранение ошибок, чтобы избежать слишком большого количества запросов:

let searchRes = searchBar.rx.text
    .orEmpty
    .filter { query in
        return query.characters.count > 4
    }
    .debounce(1, scheduler: MainScheduler.instance)
  1. результирующий строковый запрос map: ed для создания MKLocationSearch, а затем flatMapp: ed для возврата массива MKMapItems, чтобы иметь возможность привязать массив к элементам tableView:

    searchRes.map{query -> MKLocalSearch in
        let request = MKLocalSearchRequest()
        request.naturalLanguageQuery = query
        request.region = self.mapView.region
        return MKLocalSearch(request: request)
    }.flatMapLatest{search -> Observable<[MKMapItem]> in
        search.start(completionHandler:{(response, error) in
            let items: Variable<[MKMapItem]> = Variable([])
            if let resp = response {
                //need to return the result form this
                // i.e. items.value = response.mapItems
            }
            //can not return from here since the request is async
        }
    }.bindTo //continue to bind to tableview
    

Как это можно сделать с помощью RXSwift, я не нашел подходящего примера


person EmilDo    schedule 10.03.2017    source источник


Ответы (1)


Вы должны создать Observable с помощью запроса ansync. Для этого вы можете определить следующий метод:

func mapItems(for searchRequest: MKLocalSearch) -> Observable<[MKMapItem]> {
    return Observable.create { observer in
        searchRequest.start(completionHandler: { (response, error) in
            if let error = error {
                observer.onError(error)
            } else {
                let items = response?.mapItems ?? []
                observer.onNext(items)
                observer.onCompleted()
            }
        })

        return Disposables.create {
            searchRequest.cancel()
        }
    }
}

Тогда вы можете просто использовать flatMapLatest с этим методом:

searchRes
    .map { query -> MKLocalSearch in
        let request = MKLocalSearchRequest()
        request.naturalLanguageQuery = query
        request.region = self.mapView.region
        return MKLocalSearch(request: request)
    }
    .flatMapLatest{ [unowned self] search -> Observable<[MKMapItem]> in
        self.mapItems(for: search)
    }
    .bindTo(....
person joern    schedule 11.03.2017
comment
спасибо, все еще изучаю глубины RX, и эта часть всегда не была хорошо документирована - person EmilDo; 13.03.2017