#グローバルな情報(今回は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
を持たせて共有できるサンプルを作りたいです!