以前書いたこちらの記事がさっそくビルドできなくなっていたので、Swift 3.0 対応版としてリライトしました。
RxSwift のメリットを理解するには実際に使ってみるのが一番!ということで、とりあえず foursquare のベニューを取得するサンプルを作ってみました。
※RxSwift は絶賛勉強中なので間違ったことを書いている可能性が高いです。ツッコミ歓迎です!
動作環境
- Swift 3.0
- RxCocoa (3.0.0-rc.1):
- RxSwift (3.0.0-rc.1)
- SwiftyJSON (3.1.1)
- Xcode 8.0
APIクライアント
APIにアクセスする部分を作ります。戻り値を Observable<[Venue]>
にしているのがポイントです。
func search(query: String = "") -> Observable<[Venue]> { return Observable.create{ observer in let client = FoursquareAPIClient(accessToken: "YOUR_TOKEN") let parameter: [String: String] = [ "ll": "40.7,-74", "query": query ]; client.request(path: "venues/search", parameter: parameter) { [weak self] data, error in guard let strongSelf = self, let data = data else { return } let json = JSON(data: data) let venues = strongSelf.parse(venuesJSON: json["response"]["venues"]) observer.on(.next(venues)) observer.on(.completed) } return Disposables.create {} } } fileprivate func parse(venuesJSON: JSON) -> [Venue] { var venues = [Venue]() for (key: _, venueJSON: JSON) in venuesJSON { venues.append(Venue(json: JSON)) } return venues }
通信ライブラリは拙作 FoursquareAPIClient を使用しました。
ViewModel
ViewModel から先ほどの serch
を呼び出す部分です。
public func fetch(query: String = "") { client.search(query: query) .subscribe { [weak self] result in switch result { case .next(let value): self?.venues.value = value case .error(let error): print(error) case .completed: () } } .addDisposableTo(disposeBag) }
search
の戻り値が Observable<[Venue]>
なので、これを subscribe することができます。その中で、返ってくる値(ベニューリストなど)を Variable
型の venues にセットしています。この venues は ViewController から bind されるため、値が変更されるタイミングで何か処理を発火させることができるわけです。
ViewController
ViewController は30行程と、かなりスッキリしました。rx.items(dataSource: )
でベニューリストと 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.items(dataSource: self.dataSource) ) .addDisposableTo(self.disposeBag) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
完全なソースコードはこちらです。
GitHub - koogawa/RxSwiftSample: RxSwiftSample