SwiftBondとMVVMで 状態管理をシンプルにしよう

SwiftBondとMVVMで 状態管理をシンプルにしよう

SwiftBond, MVVM, Swift, Sync, wantedly, susieyy

Acbf3391de0494432a92221ffe89f34e?s=128

yohei sugigami

April 13, 2016
Tweet

Transcript

  1. 2.
  2. 3.
  3. 8.

    MVVM IUUQTNTEONJDSPTPGUDPNFOVTMJCSBSZHH W1BOE1 BTQYTFD 6*7JFX$POUSPMMFS 6*#VUUPO 6*-BCFM 6*5BCMF7JFX FUD "1*$MJFOU

    %BUB.PEFM 1FSTJTUFODF 6*-PHJD #VTJOFTT-PHJD 1SFTFOUBUJPO-PHJD ෳࡶʹͳΓ͕ͪͳ6*7JFX$POUSPMMFSʹهड़͍ͯͨ͠ ϩδοΫ͕7JFX.PEFMʹू໿͞ΕΔ 7JFX.PEFM͸ػೳ͝ͱʹ Ϋϥε෼ׂ΍ڞ௨Խ͠΍͍͢ ςετ͕͠΍͍͢ ˰ݟ௨͕͠Α͘ͳΔ
  4. 9.

    ੹຿ͱؔ৺ࣄͷ෼཭ 4UBUF 7JFX $POUSPMMFS 7JFX.PEFM %BUB ؔ஌͍ͯ͠ΔੈքΛখ͘͢͞Δ ੹຿Λ໌֬ʹ͢Δ ίʔυ͸Θ͔Γ΍͘͢ͳΔ -PHJD

    7JFX 7JFX.PEFM͸ 7JFXʹ͍ͭͯ͸ؔ஌͠ͳ͍ σʔλͷมߋ͕੹຿ PS #JOE 7JFX͸σʔλ͕ͲͷΑ͏ʹ ࡞ΒΕΔ͔͸ؔ஌͠ͳ͍ 7JFX #JOEJOH $PNNBOET
  5. 11.
  6. 20.
  7. 23.
  8. 24.

    enum RequestState { case None case Requesting case Error }

    protocol RequestListStateType { associatedtype Item var items: ObservableArray<Item> { get }
 var requestState: Observable<RequestState> { get } var hasVisibleItems: Observable<Bool> { get } var noDataViewHidden: Observable<Bool> { get } var indicatorViewHidden: Observable<Bool> { get } var retryViewHidden: Observable<Bool> { get } } Protocol 0CTFSBCMF 0CTFSBCMF"SSBZܕ͸
 4XJGU#POE͕ఏڙ͢Δػೳ
  9. 25.

    extension RequestListStateType { func binding() { items .map { $0.sequence.count

    > 0 } .bindTo(hasVisibleItems) requestState .combineLatestWith(hasVisibleItems) .map { !($0 == RequestState.Requesting && $1 == false) } .bindTo(indicatorViewHidden) requestState .combineLatestWith(hasVisibleItems) .map { !($0 == RequestState.Error && $1 == false) } .bindTo(retryViewHidden) requestState .combineLatestWith(hasVisibleItems) .map { !($0 == RequestState.None && $1 == false) } .bindTo(noDataViewHidden) } } Protocol Extension JUFNTͱSFRVFTU4UBUFͷมԽΛ ଞͷ0CTFSBCMFʹ#JOEJOH
  10. 26.

    protocol RequestListType: RequestListStateType {} extension RequestListType { func request(task: Task<ResponseCollection<Item>>)

    {
 requestState.value = .Requesting task.success { (collection: Collection<Item>) in self.requestState.value = .None self.items.array = collection.items }.failure { _ in self.requestState.value = .Error } } } Protocol Extension 3FRVFTUͷ1SPNJTF͕׬ྃͨ͠Β
 JUFNTͱSFRVFTU4UBUFʹ஋Λ୅ೖ˰ը໘͕ಈతʹมԽ 4XJGU#POE͸1SPNJTF Λఏڙ͍ͯ͠ͳ͍ͷͰखಈͰ݁߹
  11. 27.

    struct RequestListViewModel<T>: RequestListType { typealias Item = T let requestState

    = Observable<RequestState>(.None) let items = ObservableArray([])
 let hasVisibleItems = Observable<Bool>(false) let indicatorViewHidden = Observable<Bool>(true) let retryViewHidden = Observable<Bool>(true) let noDataViewHidden = Observable<Bool>(true) init() { binding() } } Protocol Implement (FOFSJDTͰ*UFNͷܕΛղܾ 7JFX.PEFMͷ࣮૷͸༻్ʹΑͬͯ࢖͍෼͚͍ͨͱ͖͕͋ΔͷͰ 1SPUPDPM&YUFOTJPOΛ׆༻ͯ͠ڞ௨Խ
  12. 29.

    let viewModel = RequestListViewModel<ContactViewModel>() override func viewDidLoad() { super.viewDidLoad( viewModel.indicatorViewHidden.bindTo(indicatorView.bnd_hidden)

    viewModel.retryViewHidden.bindTo(retryView.bnd_hidden) viewModel.noDataFirstViewHidden.bindTo(noDataView.bnd_hidden) viewModel.requestState.observeNew { UIApplication.sharedApplication() .networkActivityIndicatorVisible = ($0 == .Requesting) if $0 == .Error {
 StatusBarNotification.showWithStatus("Connection failed") } } viewModel.items.lift().bindTo(tableView, proxyDataSource: self) { 
 (indexPath, dataSource, tableView) -> UITableViewCell in let vm = dataSource[indexPath.section][indexPath.row] let cell = tableView.dequeueReusableCellWithIdentifier(
 ContactCell.identifier, forIndexPath: indexPath) as! ContactCell
 cell.configure(vm) return cell } final class ContactsViewController: UITableViewController {
  13. 30.

    viewModel.indicatorViewHidden.bindTo(indicatorView.bnd_hidden) viewModel.retryViewHidden.bindTo(retryView.bnd_hidden) viewModel.noDataFirstViewHidden.bindTo(noDataView.bnd_hidden) viewModel.requestState.observeNew { UIApplication.sharedApplication() .networkActivityIndicatorVisible = ($0 ==

    .Requesting)
 if $0 == .Error {
 StatusBarNotification.showWithStatus("Connection failed") } } COE@IJEEFO͸4XJGU#POE͕6*7JFXΛ FYUFOTJPOͨ͠GVODUJPO YYYY7JFX)JEEFOͷ஋͕มԽ͢Δͱ#JOE5Pͨ͠ 7JFXͷIJEEFO͕ಈతʹมΘΔ
  14. 31.

    viewModel.items.lift().bindTo(tableView, proxyDataSource: self) { 
 (indexPath, dataSource, tableView) -> UITableViewCell

    in let vm = dataSource[indexPath.section][indexPath.row] let cell = tableView.dequeueReusableCellWithIdentifier(
 ContactCell.identifier, forIndexPath: indexPath) as! ContactCell
 cell.configure(vm) return cell } JUFNTͷมԽΛ6*5BCMF7JFXʹ#JOEJOH ಺෦తʹ4XJGU#POE͕6*5BCMF7JFX%BUBTPVSDFͷ ࣮૷ʹͳΔͷͰɺ%BUBTPVSDFͷهड़͕ෆཁʹ Ҏ্͕Α͋͘Δ௨৴ͷྫͷ࣮૷ʹͳΓ·͢
  15. 33.

    &/%