2016-04-01 2 views
1

Je suis nouveau à RxSwift et je me demandais comment je serais en mesure d'utiliser de manière "réactive" un UIRefreshControl avec un UITableView au lieu de la façon normale de créer une cible, et en appelant manuellement beginRefreshing() et endRefreshing() .Liaison à un UIRefreshControl après un appel réseau

Par exemple, disons que je suis le chargement des chaînes d'une API:

class TableViewController: UITableViewController { 

    var data : [String] = [] 

    let db = DisposeBag() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     refreshControl = UIRefreshControl() 

     //I don't want to use 
     //refreshControl?.addTarget(self, action: #selector(getData), forControlEvents: .ValueChanged) 

     //Do something to refreshControl.rx_refreshing? 
    } 

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) 
     let str = data[indexPath.row] 
     cell.textLabel?.text = str 
     return cell 
    } 

    //MARK: - Requests 

    private func getData() { 
     let myData = MyAPI.getData() //Returns Observable<[String]> 
     myData 
      .subscribe({ [weak self] (event) in 
       switch event { 
       case .Next(let strings): 
        self?.data = strings 
        self?.tableView.reloadData() 
        break 
       case .Error(let err): 
        print(err) 
        break 
       case .Completed: 
        break 
       } 
       // self?.refreshControl?.endRefreshing() 
       }) 
      .addDisposableTo(db) 
    } 
} 

MyAPI envoie une demande pour certaines valeurs de chaîne, comment puis-je lier le refreshControl appeler getData() et arrêter aussi rafraîchissant quand il est fini (ou error'd) la demande de réseau? Ai-je besoin de lier à refreshControl.rx_refreshing?

Répondre

7

L'exemple d'application de RxSwift fournit une classe intéressante pour gérer ce type de logique: ActivityIndicator.

Une fois que vous avez ActivityIndicator dans, le code pour la reliure rx_refreshing à la demande devient vraiment facile.

let activityIndicator = ActivityIndicator() 

override func viewDidLoad() { 
    super.viewDidLoad() 

    refreshControl = UIRefreshControl() 

    // When refresh control emits .ValueChanged, start fetching data 
    refreshControl.rx_controlEvent(.ValueChanged) 
    .flatMapLatest { [unowned self] _ in 
     return self.getData() 
     .trackActivity(activityIndicator) 
    } 
    .subscribeNext { [unowned self] strings in 
     self.data = strings 
     self.tableView.reloadData() 
    } 
    .addDisposableTo(db) 

    // Bind activity indicator true/false to rx_refreshing 
    activityIndicator.asObservable() 
    .bindTo(refreshControl.rx_refreshing) 
    .addDisposableTo(db) 
} 

// getData only needs to return an observable, subscription is handled in viewDidLoad 
private func getData() -> Observable<[String]> { 
    return myData = MyAPI.getData() //Returns Observable<[String]> 
} 
+0

Merci beaucoup! Quand je l'ai essayé, j'ai dû changer 'activityIndicator.asDriver()' en 'activityIndicator.asObservable()', sinon cela donnerait que 'Value du type Driver n'a aucun membre bindTo'. Aussi, comment puis-je pousser un événement de contrôle par programmation à refreshControl? J'ai essayé 'refreshControl.beginRefreshing()', mais cela ne fonctionne pas. – jacks205

+0

Qu'essayez-vous d'accomplir en envoyant l'événement par programmation? Si vous souhaitez qu'un 'getData()' soit exécuté en premier lorsque 'viewDidLoad' est exécuté, il vaut mieux utiliser' .startWith() 'juste avant' .flatMapLatest'. J'ai mis à jour la réponse pour utiliser '.asObservable()'. – tomahh

+0

Oui, c'est ce que je voulais dire. Encore nouveau à ce truc Rx. Merci beaucoup pour l'aide! – jacks205