@cosmeアプリでのRx活用(発表者ノートつき)

11d3072d628a7b976cd2f4e6a3cf750f?s=47 aboy
November 26, 2018

 @cosmeアプリでのRx活用(発表者ノートつき)

15分ver 発表者ノートつきスライド

11d3072d628a7b976cd2f4e6a3cf750f?s=128

aboy

November 26, 2018
Tweet

Transcript

  1. 2.

    • Ѩอ༑໵ aboy • גࣜձࣾΞΠελΠϧͰɺˏcosmeΞϓϦ΍ˏcosmePROΞϓϦͷ։ൃΛ͍ͯ͠·͢ • iOSΞϓϦͱɺΞϓϦ༻APIήʔτ΢ΣΠΛ୲౰தͰ͢ • ೫໦ࡔ46͕޷͖ͳͷͰɺόΠτϧCMʹ͸͍ͭ΋ݩؾΛ͍͍͍ͨͩͯ·͢ɻdip͞Μ͸ͱͯ΋ૉ੖Β͠ ͍ͱࢥ͍ͬͯ·͢ɻ͍ͭ΋͋Γ͕ͱ͏͍͟͝·͢ɻ

    ࣗݾ঺հ ·ͣࣗݾ঺հ͍ͤͯͩ͘͞͞ɻ΅͘͸Ѩอ༑໵ͱݴ͍·ͯ͠ɺΞΠελΠϧͰҰൠੜ׆ऀ޲͚ͷˏDPTNFΞϓϦ΍ɺϏδωεϢʔβʔ޲͚ͷˏDPTNFϓϩΞϓϦͷ։ൃ Λ͍ͯ͠·͢ɻࠓ͸J04୲౰ͱɺ͋ͱ͸ͦͷΞϓϦ༻"1*ήʔτ΢ΣΠͷ։ൃΛ୲౰தͰ͢ɻ͋ͱɺ΅͘͸೫໦ࡔ͕޷͖ͳͷͰɺόΠτϧͷ$.ʹ͸େมײँ͓ͯ͠Γ ·͢ɻຊ౰ʹ͋Γ͕ͱ͏͍͟͝·͢ɻ
  2. 5.

    Rxͱ͸ʁ • Reactive Extensionsͷ͜ͱͰ͢ • Reactive Extensionsͱ͸ɺϚΠΫϩιϑτ͔Β޿·ͬͨɺReactive ProgrammingΛ࣮ݱ͢Δ ͨΊͷσβΠϯ΍ɺͦͷ࣮૷ϥΠϒϥϦͷ͜ͱͰ͢ •

    Reactive Programmingͱ͸ɺͬ͘͟Γݴ͏ͱprint(b)͕4Λग़ྗ͢ΔΑ͏ͳύϥμΠϜͰ͢ • ˏcosmeΞϓϦͰ͸ɺRxSwift(iOS)ɺRxJava(Android)Λ࢖࣮ͬͯݱ͍ͯ͠·͢ a = 1 b = 2 * a a = 2 print(b) 3Yͱ͸ɺ3FBDUJWF&YUFOTJPOTͷ͜ͱͰ͢ɻ3FBDUJWF&YUFOTJPOTͱ͸ɺ.JDSPTPGU͔Β޿·ͬͨɺ3FBDUJWF1SPHSBNNJOHΛ࣮ݱ͢ΔͨΊͷσβΠϯ΍ɺͦͷ࣮૷ϥ ΠϒϥϦͷ͜ͱͰ͢ɻͦͯ͠3FBDUJWF1SPHSBNNJOHͱ͸ɺͬ͘͟Γݴ͏ͳΒ͹ԼͷϓϩάϥϜͷQSJOU C ͕Λग़ྗ͢ΔΑ͏ͳύϥμΠϜͩͱࢥͬͯ΋Β͑Ε͹ͱࢥ͍ ·͢ɻ͜ͷίʔυ͸4XJGUͰ͕͢ɺ࣮ߦ͢ΔͱQSJOU C ͸Λग़ྗ͠·͢ɻͳͥͳΒCͷ஋͸એݴ࣌ͷBͷ஋Λ࢖ͬͯ֬ఆ͍ͯ͠Δ͔ΒͰ͢ɻ3FBDUJWF1SPHSBNNJOHͰ͸ɺ ม਺C͸ม਺BʹΛֻ͚ͨ΋ͷɺͱએݴ͞ΕΕ͹ɺBͷ஋͕มΘΔͱͦͷΠϕϯτΛτϦΨʔͱͯ͠Cͷ஋΋ߋ৽͞ΕΔɺͱ͍ͬͨ͜ͱΛ࣮ݱͰ͖·͢ɻ
  3. 6.

    Rxͱ͸ʁ • Rx͸ΦϒβʔόʔύλʔϯΛ༻͍࣮ͯ૷͞Ε͍ͯ·͢ • RxͰग़ͯ͘Δجຊతͳ֓೦Λ3ͭͬ͘͟Γઆ໌͠·͢ • Observableͱ͸ɺߪಡՄೳͰ͋ΓɺΠϕϯτΛྲྀ͢΋ͷͰ͢ • Operatorsͱ͸ɺObservableΛมԽͤ͞ΔԋࢉࢠͷΑ͏ͳ΋ͷͰ͢ •

    Subscribe(ߪಡ)ͱ͸ɺObservable͔ΒྲྀΕͯ͘ΔΠϕϯτΛ؂ࢹ͢Δ͜ͱͰ͢ 3Y͸ɺΦϒβʔόʔύλʔϯΛ༻͍࣮ͯ૷͞Ε͍ͯ·͢ɻͦΕͱɺ3YͰग़ͯ͘Δجຊతͳ֓೦Λ͜͜Ͱͭ঺հ͠·͢ɻ·ͣ0CTFSWBCMFɺ͜Ε͸ߪಡՄೳͱ͍͏ҙຯͰ ͋ΓɺΠϕϯτΛྲྀ͢΋ͷͰ͢ɻ͍ͭͮͯ0QFSBUPSTɺ͜Ε͸0CTFSWBCMFΛมԽͤ͞ΔԋࢉࢠͷΑ͏ͳ΋ͷͰ͢ɻͦͯ͠4VCTDSJCF ߪಡ ͸ɺ0CTFSWBCMF͔ΒྲྀΕͯ͘ ΔΠϕϯτΛ؂ࢹ͢Δ͜ͱͰ͢ɻίʔυͰॻ͘ͱ͜Μͳײ͡Ͱ͢ɻ
  4. 7.

    Rxͱ͸ʁ let a = BehaviorSubject<Int>(value: 1) let b: Observable<Float> =

    a .map { 2 * $0 } .map { Float($0) } b.subscribe(onNext: { (value: Float) in print(value) }) a.onNext(2) // 2.0 // 4.0 Observable Operators Subscribe ※1 ※1: BehaviorSubject͸ݫີʹ͸ObservableͰ͋ΓObserverͰ͢ ๯಄ͷBͱCͷQSJOUͷྫΛॻ͍ͯΈ·ͨ͠ɻͪΐͬͱCΛ'MPBUʹม͑ͯ͋Γ·͢ɻ·ͣBͱCΛ0CTFSWBCMFͱͯ͠એݴ͠·͢ɻCͷఆٛʹ͸0QFSBUPSTΛ࢖͍·͢ɻ 0QFSBUPST͸͜ͷΑ͏ʹνΣΠϯͤ͞Δ͜ͱ͕Ͱ͖·͢ɻ࠷ॳͷNBQΦϖϨʔλʔͰ͸Bͷ஋ʹΛ͔͚ͨ0CTFSWBCMFΛฦ͠ɺͭΊͷNBQΦϖϨʔλʔͰ͸'MPBUܕʹ ม׵ͨ͠0CTFSWBCMFΛฦ͍ͯ͠·͢ɻͦͯ͠ਅΜதͷͱ͜Ζ͕TVCTDSJCF͍ͯ͠Δ෦෼Ͱ͢ɻ͜ͷྫͩͱɺPO/FYUͱ͍͏ͷ͸ɺͬ͘͟Γਖ਼ৗܥͷΠϕϯτͩͱࢥͬͯ͘ ͍ͩ͞ɻͦΕ͕ྲྀΕ͖ͯͨͱ͖ʹQSJOU Λ͢ΔΑ͏ͳॲཧʹͳ͍ͬͯ·͢ɻBͷॳظ஋ͱมߋޙͷ΋QSJOU ͢Δ͜ͱ͕Ͱ͖·͢ɻ͜Ε͕3Yͷجຊతͳॻ͖ํʹͳ Γ·͢ɻ
  5. 12.

    • ϝϧΞυͱύεϫʔυΛೖྗͯ͠ձһొ࿥ ͕Ͱ͖Δ • ϝϧΞυͱύεϫʔυʹͦΕͧΕόϦσʔ γϣϯ͕͋Δ • ྆ํOKͩͬͨΒձһొ࿥Ϙλϯ͕༗ޮԽ • όϦσʔγϣϯ݁ՌʹԠͯ͡ΤϥʔςΩε

    τΛදࣔ ׆༻ྫɿձһొ࿥ը໘ͷσʔλόΠϯσΟϯά ͜ͷը૾ͷΑ͏ͳձһొ࿥ը໘Λߟ͑·͢ɻ࢓༷ͱͯ͠͸ɺ·ͣϝϧΞυͱύεϫʔυΛೖྗͯ͠ձһొ࿥Λ͢Δ͜ͱ͕Ͱ͖·͢ɻͦͯ͠ϝϧΞυͱύεϫʔυʹ͸ͦΕ ͧΕόϦσʔγϣϯΛ༻ҙ͠·͢ɻ྆ํͷόϦσʔγϣϯ݁Ռ͕0,Ͱ͋Ε͹ձһొ࿥Ϙλϯ͕༗ޮԽɺͭ·Γ྘৭ʹͳͬͯԡͤΔΑ͏ʹͳΓ·͢ɻύεϫʔυʹؔͯ͠ ͸ɺόϦσʔγϣϯ݁ՌʹԠͯ͡ҟͳΔΤϥʔςΩετΛදࣔͤ͞·͢ɻ͜͜ʹॻ͍ͯ͋Δ࢓༷͸͘͝Ұ෦Ͱ͚͢Ͳ΋ɺ͜Μͳը໘Λͭ͘Δͱ͖ʹ3Y͸׆༂͠·͢ɻ
  6. 13.

    class SignUpViewModel { let password = Variable<String>("") } class SignUpViewController:

    UITableViewController { @IBOutlet weak var passwordTextField: UITextField! private var viewModel: SignUpViewModel! override func viewDidLoad() { super.viewDidLoad() viewModel.password.asObservable() .bind(to: passwordTextField.rx.text) passwordTextField.rx.text.orEmpty .bind(to: viewModel.password) } } UI -> ViewModel΁ͷόΠϯσΟϯά ViewModel -> UI΁ͷόΠϯσΟϯά Input/Output݉೚ͷObservable ձһొ࿥ը໘ɿجຊతͳσʔλόΠϯσΟϯά ※1 ※1: Variable͸RxSwiftಠࣗͷ΋ͷͰɺBehaviorSubjectͷϥούʔͰ͢ɻݱࡏ͸deplicatedͰ͢ɻ ·ͣجຊతͳσʔλόΠϯσΟϯάͷ࣮૷ํ๏Λઆ໌͠·͢ɻˏDPTNFΞϓϦͰ͸7JFXʹରͯ͠7JFX.PEFMΛ༻ҙ͍ͯ͠·͢ɻ͜ͷ7JFX.PEFMʹ*OQVU༻ͷ0CTFSWBCMF ͱ0VUQVU༻0CTFSWBCMFΛ༻ҙ͠·͢ɻͪΐͬͱઆ໌ͷͨΊʹύεϫʔυͷ΋ͷ͔͠ॻ͍ͯͳ͍Ͱ͕͢ɺ·ͣύεϫʔυͷจࣈྻ͕ྲྀΕΔ0CTFSWBCMFΛ7BSJBCMFͱ͍͏ ΋ͷͰ༻ҙ͠·͢ɻ7BSJBCMFͷৄࡉͳઆ໌͸ল͖·͕͢ɺ*O0VU྆ํͰ͖Δ0CTFSWBCMFͩͱࢥ͍ͬͯͩ͘͞ɻ͜ͷQBTTXPSEͱ͍͏0CTFSWBCMFʹରͯ͠6*͔ΒόΠϯ υɺ6*΁ͷόΠϯυΛ྆ํΛॻ͘ͱɺ૒ํ޲όΠϯσΟϯά͕Ͱ͖·͢ɻ͜ͷαϯϓϧίʔυͩͱผʹ૒ํ޲όΠϯσΟϯά͢Δඞཁ͸ͳ͍ͷͰ͕͢ɺඞཁʹͳΔ৔໘͸ ͨ͘͞Μ͋Γ·͢ɻ
  7. 14.

    class SignUpViewModel { private var isEmailValid: Observable<Bool> private var isPasswordLengthValid:

    Observable<Bool> private var isPasswordCharacterValid: Observable<Bool> private var isPasswordValid: Observable<Bool> let canSignUp: Observable<Bool> init() { isEmailValid = email.asObservable() .map { (str: String) -> Bool in ϝϧΞυόϦσʔγϣϯ(str) } isPasswordCharacterValid = password.asObservable() .map { ύεϫʔυόϦσʔγϣϯ($0) } isPasswordLengthValid = password.asObservable() .map { 4 <= $0.count && $0.count <= 12 } isPasswordValid = Observable .combineLatest( isPasswordLengthValid, isPasswordCharacterValid ) { $0 && $1 } canSignUp = Observable .combineLatest(isEmailValid, isPasswordValid) { $0 && $1 } } } combineLatest͸ෳ਺ͷΞΠςϜͷ࠷৽ͷ݁ՌΛ݁߹͠ɺ ධՁؔ਺ʹج͍ͮͯม׵ͯ͠ฦ͢ΦϖϨʔλʔ map͸ΞΠςϜΛม׵͢ΔΦϖϨʔλʔ Stringܕ -> Boolܕ΁ͷม׵ (Bool, Bool)ܕ -> Boolܕ΁ͷม׵ ձһొ࿥ը໘ɿձһొ࿥Ϙλϯͷ༗ޮԽ ࣍ʹɺೖྗ͞ΕͨϝϧΞυͱύεϫʔυͷόϦσʔγϣϯ݁Ռ͕0,Ͱ͋Ε͹ɺొ࿥ϘλϯΛ༗ޮԽ͢ΔίʔυΛݟ͍͖ͯ·͢ɻϝϧΞυͷόϦσʔγϣϯɺύεϫʔυ ͷόϦσʔγϣϯ݁ՌΛฦ͢0CTFSWBCMFΛͦΕͧΕ༻ҙ͠·͢ɻ͜ͷNBQͱ͍͏ͷ͸ɺ0CTFSWBCMFͷܕΛม׵͢ΔΦϖϨʔλʔͰ͢ɻ͜͜Ͱ͸4USJOHܕΛɺ#PPMܕʹ ม׵͍ͯ͠·͢ɻ͜ͷJT&NBJM7BMJEͷ΄͏ͷNBQͷॻ͖ํ͸ΑΓஸೡͳॻ͖ํͰ͢ɻϝϧΞυ΋ύεϫʔυ΋྆ํಉ͘͡4USJOH͔Β#PPM΁ͷม׵Λ͍ͯ͠·͢ɻ ͦͯ͠ϝʔϧΞυϨεͷόϦσʔγϣϯͷ݁ՌͱɺύεϫʔυͷόϦσʔγϣϯͷ݁Ռɺͭͷ݁ՌΛड͚औͬͯɺ྆ํ0,Ͱ͋Ε͹USVFΛฦ͢Α͏ͳ0CTFSWBCMFΛ࡞ͬ ͯ͋͛·͢ɻͦΕ͕DBO4JHO6QͰ͢ͶɻDPNCJOF-BUFTUΦϖϨʔλʔ͸ෳ਺ͷετϦʔϜͷ࠷৽ͷ݁ՌΛड͚औΔ͜ͱ͕Ͱ͖·͢ɻ͜ͷ͔ͭͱ͍͏ͷ͸TXJGUͷॻ ͖ํͰɺ͜Ε͸ͭͷ#PPMܕͷҾ਺͕྆ํUSVFͩͬͨΒUSVFΛฦ͢ͱ͍͏ҙຯͰ͢ɻ͜ΕͰɺೖྗ͞ΕͨϝϧΞυͱύεϫʔυͷ஋Λ΋ͱʹొ࿥Ϙλϯͷ༗ޮඇ༗ޮԽ Λߋ৽ͤ͞ΔͨΊͷ0CTFSWBCMF͕Ͱ͖·ͨ͠ɻ͋ͱ͸
  8. 15.

    class SignUpViewController: UIViewController { @IBOutlet private weak var signUpButton: UIButton!

    private let viewModel = SignUpViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.canSignUp .bind(to: signUpButton.rx.isEnabled) } } ViewModel->UI΁ͷόΠϯσΟϯά ೖྗ͞Εͨσʔλʹج͍ͮͨ
 ొ࿥Ϙλϯͷ༗ޮ/ඇ༗ޮԽ͕࣮ݱͰ͖Δ ձһొ࿥ը໘ɿձһొ࿥Ϙλϯͷ༗ޮԽ ͜ͷDBO4JHO6QΦϒβʔόϒϧΛ6*ͷ΄͏ͰαϒεΫϥΠϒͯ͠ɺ6*ͷঢ়ଶʹόΠϯσΟϯάͤ͞ΔΑ͏ʹ͢Ε͹0,Ͱ͢ɻϘλϯ͸JT&OBCMFEͱ͍͏#PPMܕͷ༗ޮԽ ඇ༗ޮԽΛ؅ཧ͢ΔϓϩύςΟΛ͍࣋ͬͯΔͷͰɺ͍ͭ͜ʹόΠϯυͤ͞·͢ɻ͜ΕͰσʔλόΠϯσΟϯάΛར༻ͨ͠ɺձһొ࿥ϘλϯͷϦΞϧλΠϜͷঢ়ଶมԽΛ࣮ ݱ͍ͯ͠·͢ɻ
  9. 16.

    class SignUpViewModel { private var isPasswordLengthValid: Observable<Bool> private var isPasswordCharacterValid:

    Observable<Bool> let passwordInvalidText: Observable<String> init() { isPasswordCharacterValid = password.asObservable() .map { ύεϫʔυόϦσʔγϣϯ($0) } isPasswordLengthValid = password.asObservable() .map { 4 <= $0.count && $0.count <= 12 } passwordInvalidText = Observable .combineLatest(isPasswordCharacterValid, isPasswordLengthValid) .map({ (charValid: Bool, lenValid: Bool) -> String in if !charValid { return "ύεϫʔυʹ࢖༻Ͱ͖ͳ͍จࣈؚ͕·Ε͍ͯ·͢ɻ" } else if !lenValid { return "ύεϫʔυ͸4จࣈҎ্ɺ12จࣈҎ಺Ͱೖྗ͍ͯͩ͘͠͞ɻ" } return "" }) } } όϦσʔγϣϯ݁ՌʹԠͨ͡ςΩετΛฦ͢ ձһొ࿥ը໘ɿόϦσʔγϣϯ݁ՌͷΤϥʔςΩετ ࣍͸όϦσʔγϣϯ݁ՌʹԠͯ͡ΤϥʔςΩετΛදࣔͤ͞Δ৔߹Ͱ͢ɻ·ͨઆ໌ͷͨΊʹύεϫʔυͷ৔߹͚ͩݟ͍͖ͯ·͢ɻ͖͞΄Ͳ·Ͱͷஈ֊Ͱɺύεϫʔυͷό ϦσʔγϣϯछྨɺจࣈͷόϦσʔγϣϯͱจࣈ਺ͷόϦσʔγϣϯΛͦΕͧΕ0CTFSWBCMFͱͯ͠ఆٛͯ͋͠Γ·͢ͷͰɺͦͷͭͷ0CTFSWBCMFΛ݁߹ͯ͠ɺ৚݅ʹ ͋ͬͨจࣈྻʹม׵ͨ͠0CTFSWBCMFΛ࡞ͬͯ͋͛Ε͹͍͍͚ͩͰ͢ͶɻͰɺ͜ͷQBTTXPSE*OWBMJE5FYUͱ͍͏0CTFSWBCMFΛ
  10. 17.

    class SignUpViewController: UIViewController { @IBOutlet private weak var passwordInvalidLabel: UILabel!

    private let viewModel = SignUpViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.isPasswordInvalidLabelHidden .bind(to: passwordInvalidLabel.rx.isHidden) viewModel.passwordInvalidText .bind(to: passwordInvalidLabel.rx.text) } } ձһొ࿥ը໘ɿόϦσʔγϣϯ݁ՌͷΤϥʔςΩετ Model->UI΁ͷόΠϯσΟϯά ·ͨಉ͡Α͏ʹ6*ͷϓϩύςΟʹόΠϯυͤ͞·͢ɻجຊతʹɺ৚݅ʹΑͬͯඇදࣔʹͳΔ6*΋ؚΊͯը໘ʹ͸શͯઃஔ͓͍ͯͯ͠ɺJT)JEEFOϓϩύςΟΛૢ࡞ͯ͠ද ࣔඇදࣔΛ੾Γସ͑Δํ๏Λ࢖ͬͯ·͢ɻ͜ΕͰձһొ࿥ը໘ͷ࿩͸͓͠·͍Ͱ͢ɻ
  11. 20.

    class ThreadsViewModel { private let timer: Observable<Int> let polling: Observable<Thread>

    init(repo: ThreadRepositoryProtocol = ThreadRepository()) { timer = Observable<Int> .interval(10.0, scheduler: MainScheduler.instance) polling = timer .flatMapFirst({ (_) -> Observable<[Thread]> in return repo.fetchThreads() }) .filter { ߋ৽͕͋Δ͔($0) } } } ϝοηʔδεϨουϦετͷϙʔϦϯά intervalΦϖϨʔλʔ
 ҰఆִؒͰΠϕϯτΛൃߦ flatMapFirstΦϖϨʔλʔ
 ม׵ & ॲཧத͸ແࢹ filterΦϖϨʔλʔ
 trueͳΒΠϕϯτΛૹΔ 3YΛ࢖͏ͱίʔυ͸͜Μͳײ͡Ͱ͢ɻ·ͣUJNFSΦϒβʔόϒϧͱQPMMJOHΦϒβʔόϒϧΛએݴͯ͋͛͠·͢ɻҰఆִؒͰͳʹ͔͢Δɺͱ͍͏ͷ͸JOUFSWBMΦϖϨʔλʔ ͳͲͰ࣮ݱͰ͖·͢ɻͦͯ͠QPMMJOHΦϒβʔόϒϧ͸ɺUJNFSΦϒβʔόϒϧΛ0QFSFUPSTͰม׵͠·͢ɻqBU.BQ'JSTUΦϖϨʔλʔ͸ɺ஋ͷม׵ͱɺͬ͘͟Γ͍͏ͱॲ ཧதʹ৽͖ͨ͘͠ΠϕϯτΛແࢹ͢ΔޮՌ͕͋Γ·͢ɻ"1*௨৴ʹ͕͔͔࣌ؒͬͯͭ·͍ͬͯͯ΋ɺUJNFSΦϒβʔόϒϧ͕ΩϡʔͷΑ͏ʹͨ·Γଓ͚Δ͜ͱ͕ͳ͘ͳΓ ·͢ɻͦͯ͠qJUFSΦϖϨʔλʔͰεϨουʹߋ৽͕͔͋ͬͨͲ͏͔Λ൑ఆͯ͠ɺߋ৽͕͋Ε͹ΠϕϯτΛ6*·Ͱྲྀͯ͠ɺ6*ͷ΄͏Ͱߋ৽ॲཧΛߦ͍·͢ɻ͜ΕͰϙʔϦϯ άͷ঺հ͸Ҏ্Ͱ͢ɻ
  12. 22.

    • ͻͱͭͷը໘ʹෳ਺ηΫγϣϯ(ෳ਺छྨͷίϯςϯπ) Λදࣔ • ηΫγϣϯ͸औಘͰ͖ͨ΋ͷ͔Βදࣔ • ηΫγϣϯ1͸ɺෳ਺ͷAPI͔Βෳ਺ͷσʔλΛऔಘͯ͠ දࣔɻAPIͷ݁ՌΛશͯ଴ͭ ׆༻ྫɿඇಉظAPI௨৴ॲཧͷ૊Έ߹Θͤ ηΫγϣϯ1

    ηΫγϣϯ2 ηΫγϣϯ3 ͜ͷը໘͸ɺҰͭͷը໘ʹෳ਺ηΫγϣϯΛදࣔ͢ΔϦετϏϡʔͱͳ͍ͬͯ·͢ɻηΫγϣϯ͸औಘͰ͖ͨ΋ͷ͔Βදࣔ͢ΔͷͰɺฒྻͰऔಘ͢Δඞཁ͕͋Γ·͢ɻ͞ ΒʹɺҰ൪্ͷΧϧʔηϧ6*ʹͳ͍ͬͯΔηΫγϣϯ͸ɺදࣔ͢ΔͨΊͷσʔλ͕਺छྨ͋ͬͯɺ໰͍߹Θͤํ๏͕ҧ͏ͷͰɺͦΕΒશͯͷ݁ՌΛ଴͔ͬͯΒදࣔ͢Δɺ ͱ͍͏࢓༷ʹͳͬͯ·͢ɻ
  13. 23.

    class ViewModel { private let cosme1: Observable<Cosme> private let cosme2:

    Observable<Cosme> private let cosme3: Observable<Cosme> let section1: Observable<Void> init() { section1 = Observable .zip(cosme1, cosme2, cosme3) .map { ม׵ॲཧ } } } ඇಉظAPI௨৴ॲཧͷ૊Έ߹ΘͤɿηΫγϣϯ̍ͷ࣮૷ zipͰඞཁͳObservableΛ·ͱΊΔ
 Πϕϯτ͸଴ͪ߹ΘͤΔ ͜ΕΛίʔυͰݟ͍͖ͯ·͢ɻ·ͣηΫγϣϯͷ࣮૷͸͜ͷΑ͏ʹͳΓ·͢ɻDPTNF  ͸ͦΕͧΕηΫγϣϯͷදࣔʹඞཁͳσʔλΛ"1*ܦ༝Ͱऔಘ͢Δ 0CTFSWBCMFͩͱࢥ͍ͬͯͩ͘͞ɻͦΕΒΛ[JQΦϖϨʔλʔͰ݁߹͠·͢ɻ[JQΦϖϨʔλʔ͸ɺෳ਺ͷ0CTFSWBCMFͷΠϕϯτΛ݁߹͠·͕͢ɺΠϕϯτͷ଴ͪ߹ΘͤΛ ߦͳͬͯҰؾʹૹ৴͞Ε·͢ɻͳͷͰDPTNF  શ͔ͯΒΠϕϯτ͕ྲྀΕͯ͘ΔͷΛ଴ͪ·͢ɻ͜ΕͰઌ΄ͲݴͬͨηΫγϣϯͷ࢓༷͸ΫϦΞͰ͢ɻ
  14. 24.

    class ViewModel { private let cosme1: Observable<Cosme> private let cosme2:

    Observable<Cosme> private let cosme3: Observable<Cosme> let section1: Observable<Section1> let sectionList: Observable<[Section]> init() { section1 = Observable .zip(cosme1, cosme2, cosme3) .map { ม׵ॲཧ } sectionList = Observable .merge(section1, section2, section3) .map { ม׵ॲཧ } } } ඇಉظAPI௨৴ॲཧͷ૊Έ߹ΘͤɿऔಘͰ͖ͨηΫγϣϯ͔Βදࣔ mergeͰඞཁͳObservableΛ·ͱΊΔ
 Πϕϯτ͸଴ͪ߹Θͤ͠ͳ͍ zipͰඞཁͳObservableΛ·ͱΊΔ
 Πϕϯτ͸଴ͪ߹ΘͤΔ ࠓ౓͸ը໘શମͷ࢓༷ɺͭ·ΓऔಘͰ͖ͨTFDUJPO͔Βॱ࣍දࣔɺͱ͍͏ͷΛͲ͏࣮૷͢Δ͔Ͱ͕͢ɺࠓ౓͸NFSHFΦϖϨʔλʔΛ࢖͍·͢ɻNFSHFΦϖϨʔλʔ͸[JQ ಉ༷ෳ਺ͷ0CTFSWBCMFΛ݁߹͠·͕͢ɺΠϕϯτ͕ૹΒΕ͖ͯͨॱʹͭͲૹ৴͞Ε·͢ɻͳͷͰ֤ηΫγϣϯͷ0CTFSWBCMFΛNFSHFͰ݁߹ͨ͠TFDUJPO-JTUͱ͍͏ 0CTFSWBCMFΛ༻ҙͯ͋͛ͯ͠ɺ͋ͱ͸͜ΕΛ
  15. 25.

    class ViewController: UIViewController { @IBOutlet private weak var tableView: UITableView!

    private let viewModel = ViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.sectionList.subscribe(onNext: { [weak self] (_) in self?.tableView.reloadData() }) } } ඇಉظAPI௨৴ॲཧͷ૊Έ߹ΘͤɿऔಘͰ͖ͨηΫγϣϯ͔Βදࣔ ηΫγϣϯͷϦετ͕ߋ৽͞ΕΔͨͼʹUIΛߋ৽ ը໘ͷ΄͏ͰɺTFDUJPO-JTUΛTVCTDSJCFͯ͠ɺ౎౓ը໘Λߋ৽ͯ͋͛͠Δ͜ͱͰɺσʔλ͕औಘͰ͖ͨηΫγϣϯ͔Βදࣔ͢Δ͜ͱ͕Ͱ͖ΔΑ͏ʹͳΓ·͢ɻ͜͏΍ͬ ͯඞཁͳ0CTFSWBCMFΛఆٛͯ͋͛ͯ͠ɺͦΕΒΛ૊Έ߹ΘͤΔ͜ͱʹΑͬͯɺ࢓༷ʹͦͬͨඇಉظॲཧΛ࡞Γ্͍͖͛ͯ·͢ɻ׆༻ྫͷ঺հ͸Ҏ্Ͱ͓͠·͍Ͱ͢ɻ
  16. 26.

    • ˏcosmeΞϓϦͰͷRx׆༻ྫΛ঺հ͠·ͨ͠ɻσʔλόΠϯσΟϯάػߏ΍ɺObservableΛ૊Έ߹Θͤ ͯඇಉظॲཧΛॻ͚Δ఺͸ັྗతʹײ͍ͯ͡·͢ɻجຊతʹΞϓϦέʔγϣϯશମͰRx͕࢖ΘΕ͍ͯ·͢ • Rx͸ݴޠʹΑΒͳ͍֓೦ͳͷͰɺ࣮૷ϥΠϒϥϦؒͷࠩҟΛআ͚͹ɺiOS/AndroidΤϯδχΞؒͰͷڞ ௨ݴޠͱͯ͠ػೳ͢ΔϝϦοτ΋͋Γ·͢ • σʔλͷ௥͍ʹ͘͞΍Մಡੑɺֶशʹ౤ࢿͰ͖Δ͔ɺͳͲͷ؍఺ͰɺνʔϜ։ൃͰ࠾༻͢Δ͔Ͳ͏͔͸ͦ ͷ࣌ͦͷ࣌ʹΑͬͯݟۃΊΔඞཁ͕͋Δ͔ͱࢥ͍·͢ •

    ωΠςΟϒΞϓϦք۾Ͱ͸ؔ৺౓ͷߴ͍ٕज़Ͱ͸͋Δͱࢥ͏ͷͰɺ͜Ε͔Β΋΢Υον͍ͯ͘͠ͱ͍͍͔ ͱࢥ͍·͢ • ReactiveXͱ͍͏αΠτʹυΩϡϝϯτ΍֤ݴޠͷRxϥΠϒϥϦ͕·ͱ·͍ͬͯΔͷͰ͝ཡ͍ͩ͘͞
 http://reactivex.io/ ͓ΘΓʹ ࠷ޙͰ͕͢ɺࠓճ͸!DPTNFΞϓϦͰͷ3Y׆༻ྫΛগ͠঺հ͠·ͨ͠ɻࠓճ঺հͰ͖ͨͷ͸΋ͪΖΜҰྫͰɺجຊతʹΞϓϦέʔγϣϯશମͰ3Y͕࢖ΘΕ͍ͯ·͢ɻ ͜͏࣮ͨ͠૷্ͷϝϦοτʹՃ͑ͯɺ3Y͸ݴޠʹΑΒͳ͍֓೦ͳͷͰɺ3Y4XJGU΍3Y+BWBͱ͍࣮ͬͨ૷ϥΠϒϥϦؒͰͷࠩҟΛআ͚͹ɺJ04"OESPJEΤϯδχΞؒɺҟ ͳΔϓϥοτϑΥʔϜͷΤϯδχΞؒͰͷڞ௨ݴޠͱͯ͠ɺίϛϡχέʔγϣϯʹ࢖͑Δͱ͍͏ϝϦοτ΋͋Γ·͢ɻ ্ͨͩهͷϝϦοτ͸͔ͨ͠ʹײ͍ͯ͡Δ൓໘ɺετϦʔϜ͕ࢄΒ͹Δ͜ͱ͔Βσʔλͷ௥͍ʹ͘͞΍Մಡੑɺ·ͨ3Yͱ͍͏֓೦΍࣮૷ϥΠϒϥϦͷֶशʹ૊৫ͱͯ͠ ౤ࢿͰ͖Δ͔Ͳ͏͔ɺͱ͍ͬͨ؍఺ͰɺνʔϜ։ൃͰ࠾༻͢Δ͔Ͳ͏͔͸ɺਖ਼௚·ͩ·ͩҙݟ͕Θ͔ΕΔͱ͜Ζ͔ͱࢥ͍·͢ɻͦ΋ͦ΋ͷίʔυͷॻ͖ํ͕มΘΔͷͰɺ ʮͱΓ͋͑ͣ࢖͑͹0,ʯͱ͍͏ٕज़Ͱ͸ͳ͍ͷͰɺͦͷ࣌ͦͷ࣌Ͱ͔ͬ͠Γߟ͑Δඞཁ͕͋Δ͔ͱࢥ͍·͢ɻͦΜͳ3YͰ͕͢ɺࡢ೥ͷJ04%$Ͱ͸ʮ3Y4XJGUͷ 0CTFSWBCMFͱ͸Կ͔ʁʯͱ͍͏τʔΫ͕ϕεττʔΫ৆ΛͱΓ·ͨ͠͠ɺ3YͰ։ൃ͍ͯ͠Δͱ͍͏ݱ৔ͷ࿩͸ͨ͘͞Μฉ͖·͢ɻωΠςΟϒΞϓϦք۾Ͱ͸ؔ৺౓ͷߴ ͍ٕज़ͩͱࢥ͍·͢ͷͰɺ͜Ε͔Β΋΢Υον͍ͯ͘͠ͱ͍͍͔ͱࢥ͍·͢ɻ3FBDUJWF9ͱ͍͏αΠτʹ͍Ζ͍Ζ·ͱ·ͬͯ·͢ͷͰɺ͝ཡʹͳͬͯΈ͍ͯͩ͘͞ɻҎ্ ͰɺൃදΛऴΘΓ·͢ɻ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ