グローバルな情報(今回はLikeの情報)を複数の画面間で共有する!
SNS系のアプリなどを作る際にグローバルな情報を複数の画面間で共有しないといけない場合がありますよね!例えばLikeの情報など
今回はユーザーが変更したこのLikeの情報をどうやって複数の画面で共有するかをRxSwiftを使って実践してみました。
サンプルコードはこちら!(Sample5です)
実際何をしているのか
今回はAPI通信はせずにローカルだけで情報の共有を実装して、cellにもCellModelを保持させていません。
*Twitter APIを利用してAPI通信も行うサンプルを実装予定
やったこと
- RxSwiftを使ってタイムラインを表示(TableView)
- 詳細画面に遷移後Likeボタンを押してLike情報を更新 → タイムラインの画面でもその情報をもとにLike情報をアップデート!!!
ステップ1: オブジェクトをTableViewに表示
はじめにItemというモデルを作成します。
struct Item {
let id: Int
let name: String
var isLiked: Bool
}
そしてDriver.justを使ってObservableなオブジェクトを作成し、rx_itemsWithCellIdentifierを使ってTableViewに対してバインドを行います!
let items = Driver.just([
Item(id: 1, name: "Instagram", isLiked: false),
Item(id: 2, name: "Facebook", isLiked: true),
Item(id: 3, name: "Twitter", isLiked: false),
Item(id: 4, name: "Mercari", isLiked: true),
Item(id: 5, name: "Atte", isLiked: false),
Item(id: 6, name: "Line", isLiked: true)
])
items
.drive(tableView.rx_itemsWithCellIdentifier("Cell", cellType: Sample5TableViewCell.self)) { index, item, cell in
cell.item = item
}
.addDisposableTo(disposeBag)
これでオブジェクトをTableViewに表示できました!
どうやって情報を複数の画面間で共有するのか?
今回Like情報を共有するにあたってRxSwiftのPublishSubjectを利用しています。
class LikeSubject {
static let ItemDidLikeNotification = PublishSubject<Item>()
}
PublishSubjectは自身がObserverにもObservableにもなれる便利なものです。
これを使用してLike情報を更新した時に更新されたitemをこのPublishSubjectに流します!
見ての通り購読したタイミングより前のオブジェクトはストリームには流れてきません。
詳細画面のボタンのタップに応じてLike情報を更新してグローバルな川に流す。
ここでしていること
- ボタンタップのストリームを作成する。
-
ItemのLike情報をmap内で更新する。 - ボタンタップのストリームを利用して、更新された
ItemをPublishSubjectへ流す。 - 同じボタンタップのストリームを利用してボタンの文字を変える。
let buttonTapped = likeButton.rx_tap.asDriver()
buttonTapped
.map { [unowned self] _ -> Item in
var item = self.item
item.isLiked = item.isLiked ? false : true
return item
}
.driveNext { updatedItem in
LikeSubject.ItemDidLikeNotification
.onNext(updatedItem)
}
.addDisposableTo(disposeBag)
buttonTapped
.driveNext { [weak self] _ in
guard let strongSelf = self else { return }
if strongSelf.item.isLiked {
strongSelf.likeButton.setTitle("👎🏻ライクされていません", forState: .Normal)
} else {
strongSelf.likeButton.setTitle("👍🏻ライクされています", forState: .Normal)
}
}
.addDisposableTo(disposeBag)
ここでアップデートされたitemをグローバルなLikeSubject.ItemDidLikeNotificationにonNextしています。
この場合はPublishSubjectをobserverとして利用しています。
.driveNext { updatedItem in
LikeSubject.ItemDidLikeNotification
.onNext(updatedItem)
}
.addDisposableTo(disposeBag)
グローバルに流れてきたitemを購読して、タイムラインのLike情報を更新する。
グローバルなLikeSubject.ItemDidLikeNotificationをcellにitemを渡してあげているところで購読してあげます。
ここでしていること
-
LikeSubject.ItemDidLikeNotificationに流れてくるitemを購読する。 -
filterを使って流れてきたitemがtableViewに表示するものと同じidの時だけフィルターする。 -
cellに新しく流れてきたitemを渡してあげる。
items
.drive(tableView.rx_itemsWithCellIdentifier("Cell", cellType: Sample5TableViewCell.self)) { index, item, cell in
cell.item = item
cell.disposeBag = DisposeBag()
LikeSubject.ItemDidLikeNotification
.filter { $0.id == item.id }
.subscribeNext { [weak cell] item in
cell?.item = item
}
.addDisposableTo(cell.disposeBag)
}
.addDisposableTo(disposeBag)
これで詳細画面でのLikeの変化を元のタイムラインでも共有できるようになりました!
次にやりたいこと!
次はローカルだけでなくて、実際にTwitterかなにかのAPIを利用して、そしてcellにcellModelを持たせて共有できるサンプルを作りたいです!