kmb
kmb

Reputation: 41

RxSwift reload tableview

let officialAccountObservable : Observable<[SearchUser]> = SearchAPI.sharedAPI.suggestAccounts()

        officialAccountObservable.bind(to: tableView.rx.items(cellIdentifier: "followcell", cellType: FollowCell.self)) {
            (index, user , cell) in
            if user.profileImagePath.isEmpty == false {
                cell.profile.af_setImage(withURL: URL.init(string: user.profileImagePath)!)
            }else {
                cell.profile.image = UIImage.init(named: "icon_user_03")
            }
            cell.nickName.text = user.nickName

            cell.follow.rx.tap
                .debounce(0.3, scheduler: MainScheduler.instance)
                .subscribe(onNext: {
                    [unowned self] in
                    cell.setFollow(user: user, completion: { (result) in
                        if(result == true){

                        }
                    })
                }).addDisposableTo(self.disposeBag)
        }.addDisposableTo(disposeBag)

func suggestAccounts() -> Observable<[SearchUser]> {

    let uri = Constants.VyrlSearchURL.suggestUsers

    return Observable.create { observer in
        let request = Alamofire.request(uri, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: Constants.VyrlAPIConstants.getHeader()).responseArray { (response: DataResponse<[SearchUser]>) in
            let value = response.result.value

            observer.onNext(value!)
            observer.onCompleted()
        }

        return Disposables.create(with: request.cancel)
    }
}

I want to reload the table view in code (result == true) For reload, OfficialAccountObservable must be received. My code is all over and I wonder how I can update it in that state.

Upvotes: 4

Views: 5225

Answers (3)

xxtesaxx
xxtesaxx

Reputation: 6429

I think the problem you are having right now is that when you create the observable which makes the Alamofire call, it only ever gets executed once since you have no way to make another call.

What you might want to do is something like Maxim Volgin suggested: use a subject.

A subject is a input as well as a output at the same time. In your case, the output would be the data for your tableview and you would bind it as you already do.

Then, use the pull to refresh or another suiting mechanism for reloading to make the web service call and publish the results to the subject (which then will update your tableview).

Keep in mind that subjects also populate onError and onComplete calls up to the observer so make sure you deal with possible errors in your web service call before publishing the result to the subject.

I found this site incredible helpful to get a better understanding of RxSwift: http://swiftpearls.com/

You should check it out. Especially the RxSwift for Dummies is great to get the basic understanding of how things are supposed to work.

Upvotes: 1

Maxim Volgin
Maxim Volgin

Reputation: 4077

AFAIK, this is the standard way of doing this -

let source = PublishSubject<Observable<[SearchUser]>>()
let officialAccountObservable: Observable<[SearchUser]> = source.switchLatest()
source.onNext(suggestAccounts()) // every call will refresh your table

Upvotes: 4

Timofey Solonin
Timofey Solonin

Reputation: 1403

I recommend you to create a Refreshable decorator.

class Refreshable<T>: ObservableType {

    typealias E = T
    func subscribe<O:ObserverType>(_ observer: O) -> Disposable where O.E == E {
        return refreshMeans
            .flatMapLatest{ [unowned self] in
                return self.origin.asObservable()
            }
            .subscribe(observer)
    }

    private let disposeBag = DisposeBag()
    private let origin: Observable<T>
    init(origin: Observable<T>, updatedOn: Observable<Void> = .never()) {
        self.origin = origin
        updatedOn.bind(to: refreshMeans).disposed(by: disposeBag)
    }

    private let refreshMeans = BehaviorSubject<Void>(value: ())

    func refresh() {
        refreshMeans.on(.next())
    }

}

wrap your officialAccountObservable into a Refreshable:

let officialAccountObservable : Refreshable<[SearchUser]> = Refreshable(origin: SearchAPI.sharedAPI.suggestAccounts())

and call refresh when you need to refresh it:

if(result == true){
    officialAccountObservable.refresh()
}

Upvotes: 2

Related Questions