Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

SwiftBond, MVVM, Swift, Sync, wantedly, susieyy

yohei sugigami

April 13, 2016
Tweet

More Decks by yohei sugigami

Other Decks in Technology

Transcript

  1. 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͸ػೳ͝ͱʹ Ϋϥε෼ׂ΍ڞ௨Խ͠΍͍͢ ςετ͕͠΍͍͢ ˰ݟ௨͕͠Α͘ͳΔ
  2. ੹຿ͱؔ৺ࣄͷ෼཭ 4UBUF 7JFX $POUSPMMFS 7JFX.PEFM %BUB ؔ஌͍ͯ͠ΔੈքΛখ͘͢͞Δ ੹຿Λ໌֬ʹ͢Δ ίʔυ͸Θ͔Γ΍͘͢ͳΔ -PHJD

    7JFX 7JFX.PEFM͸ 7JFXʹ͍ͭͯ͸ؔ஌͠ͳ͍ σʔλͷมߋ͕੹຿ PS #JOE 7JFX͸σʔλ͕ͲͷΑ͏ʹ ࡞ΒΕΔ͔͸ؔ஌͠ͳ͍ 7JFX #JOEJOH $PNNBOET
  3. 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͕ఏڙ͢Δػೳ
  4. 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
  5. 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 Λఏڙ͍ͯ͠ͳ͍ͷͰखಈͰ݁߹
  6. 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Λ׆༻ͯ͠ڞ௨Խ
  7. 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 {
  8. 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͕ಈతʹมΘΔ
  9. 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ͷهड़͕ෆཁʹ Ҏ্͕Α͋͘Δ௨৴ͷྫͷ࣮૷ʹͳΓ·͢
  10. &/%