読者です 読者をやめる 読者になる 読者になる

koogawa log

iOS、Android、foursquareに関する話題

RxSwiftを使ってfoursquareのベニューを取得するメモ

iOS Swift Reactive

2016.10.23 追記:Swift 3.0 対応版を作成しました

blog.koogawa.com


RxSwift のメリットを理解するには実際に使ってみるのが一番!ということで、とりあえず foursquare のベニューを取得するサンプルを作ってみました。

f:id:koogawa:20160515223640p:plain

※RxSwift は絶賛勉強中なので間違ったことを書いている可能性が高いです。ツッコミ歓迎です!

動作環境

  • Swift 2.2
  • RxCocoa (2.4)
  • RxSwift (2.4)
  • SwiftyJSON (2.3.2)
  • Xcode 7

APIクライアント

APIにアクセスする部分を作ります。戻り値を Observable<[Venue]> にしているのがポイントです。

func send() -> Observable<[Venue]> {
    return Observable.create{ (observer) in
        let client = FoursquareAPIClient(accessToken: "YOUR_TOKEN")
        let parameter: [String: String] = [
            "ll": "40.7,-74",
        ];
        client.requestWithPath("venues/search", parameter: parameter) {
            [weak self] (data, error) in
            let json = JSON(data: data!)
            let venues = (self?.parseVenues(json["response"]["venues"])) ?? [Venue]()
            observer.on(.Next(venues))
            observer.on(.Completed)
        }
        return AnonymousDisposable {}
    }
}

func parseVenues(venuesJSON: JSON) -> [Venue] {
    var venues = [Venue]()
    for (key: _, venueJSON: JSON) in venuesJSON {
        venues.append(Venue(json: JSON))
    }
    return venues
}

通信ライブラリは拙作 FoursquareAPIClient を使用しました。

ViewModel

ViewModel から先ほどの send を呼び出す部分です。

public func fetch() {
    self.send()
        .subscribe { [weak self] (event) -> Void in
            switch event {
            case .Next(let value):
                self?.venues.value = value
            case .Error(_):
                ()
            case .Completed:
                ()
            }
        }
        .addDisposableTo(disposeBag)
}

戻り値が Observable<[Venue]> なので、これを subscribe して、返ってくる値(ベニューリストなど)を処理しています。

ViewController

ViewController は30行程と、かなりスッキリしました。rx_itemsWithDataSource でベニューリストとTableViewをBindしているのがポイントです。ViewModel のベニューリストに変化があるとTableViewがリロードされます。

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    
    var viewModel = ViewModel()
    var dataSource = DataSource()
    var delegate = Delegate()
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self.delegate
        self.viewModel.fetch()
        self.viewModel.venues
            .asDriver()
            .drive (
                self.tableView.rx_itemsWithDataSource(self.dataSource)
            )
            .addDisposableTo(self.disposeBag)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

完全なソースコードはこちらです。

GitHub - koogawa/RxSwiftSample: RxSwiftSample

参考にさせて頂いた記事など