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

SwiftとFunctional Reactive Programming

shtnkgm
October 02, 2018

SwiftとFunctional Reactive Programming

About
- Swift
- Functional Reactive Programming
- RxSwift

shtnkgm

October 02, 2018
Tweet

More Decks by shtnkgm

Other Decks in Programming

Transcript

  1. ղ౴ྫ1 1͔Β10·Ͱͷ੔਺Λ3ഒͯ͠ɺ6ͷഒ਺ͷΈ഑ྻΛੜ੒ var result = [Int]() for number in 1...10

    { let tripleNumber = number * 3 if tripleNumber % 6 == 0 { result += [tripleNumber] } }
  2. ղ౴ྫ1ʣ໋ྩܕϓϩάϥϛϯά var result = [Int]() for number in 1...10 {

    let tripleNumber = number * 3 if tripleNumber % 6 == 0 { result += [tripleNumber] } } ղ౴ྫ2ʣએݴܕϓϩάϥϛϯάʢதͰ΋ؔ਺ܕʣ let result = (1...10).map { $0 * 3 }.filter { $0 % 6 == 0 }
  3. ໋ྩܕ ! એݴܕ " ண໨ How ʢखଓ͖ʣ What ʢग़ྗͷੑ࣭ʣ ߏ଄

    forϧʔϓ/৚݅෼ذ Λଟ༻ ؔ਺Λܨ͛Δ ʢؔ਺ܕʣ ঢ়ଶͷมߋ varʢεςʔτϑϧʣ letʢεςʔτϨεʣ
  4. // Πϝʔδ ---1---2---3---4---|(completed)---> // ίʔυ Observable<Int> .of(1, 2, 3, 4)

    // ετϦʔϜΛੜ੒ .subscribe { print($0) } // ετϦʔϜΛ؂ࢹ .dispose() // ετϦʔϜΛഁغ
  5. // Πϝʔδ ---͋---͍͋---͍͋͏---͍͋͏͑---͍͋͏͓͑---> // ίʔυ textField.rx.text.asObservable() // ೖྗςΩετΛετϦʔϜʹม׵ .map {

    String($0.count) } // จࣈྻΛจࣈ਺ʹม׵ .bindTo(label.rx.text) // ϥϕϧʹ൓ө .disposed(by: disposeBag)
  6. // Πϝʔδ --- ! --- " --- # --- !

    --- " --- ! ---> filterͰͿͲ͏͚ͩͷετϦʔϜʹม׵͢ΔΑ --- ! --- ! --- ! ---> // ίʔυ Observable<String> .from([" ! ", " " ", " # ", " ! ", " " ", " "]) // ഑ྻ͔ΒετϦʔϜΛੜ੒ .filter( $0 == " ! ") // ετϦʔϜΛม׵ .subscribe { print($0) } .dispose()
  7. // Πϝʔδ ---Ϩεϙϯε---|(completed)---> ΋͘͠͸ ---×(eror)---> // ίʔυ Observable<T>.create { observer

    -> Disposable in // ؔ਺͔ΒετϦʔϜΛੜ੒ APIClient.request() { response in switch response.result { case .success: observer.onNext(response) // nextΛૹ৴ observer.onCompleted() // completedΛૹ৴ case .failure(let error): observer.onError(error) // errorΛૹ৴ } } return Disposables.create() }
  8. @IBAction func buttonTapped() { label.text = "loading..." apiRequest() } func

    apiRequest() { userInfoModel.request { [weak self] result in switch result { case .success(let userInfo): self?.repositoryListModel.request(userId: userInfo.userId) { result in switch result { case .success(let repositoryList): self?.label.text = repositoryList.map { $0.title }.joined(separator: "\n") case .failure(let error): print(error) } } case .failure(let error): print(error) } } }
  9. func rxRequest(api: API) -> Observable<T> { return Observable<T>.create { observer

    -> Disposable in Alamofire.request(api.urlString, method: api.method, parameters: api.parameters) .validate(statusCode: 200..<300) .responseJSON { response in switch response.result { case .success: do { guard let jsonData = response.data else { observer.onError(APIClientError.emptyResponseError) return } let jsonDecoder = JSONDecoder() jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase let data = try jsonDecoder.decode(T.self, from: jsonData) observer.onNext(data) observer.onCompleted() } catch { observer.onError(APIClientError.parseError(error)) } case .failure(let error): observer.onError(APIClientError.connectionError(error)) } } return Disposables.create() } }
  10. struct UserInfoModel { typealias ResponseType = UserInfo private let apiClient:

    APIClient<ResponseType> init(apiClient: APIClient<ResponseType> = APIClient()) { self.apiClient = apiClient } func request(completion: @escaping (Result<ResponseType>) -> Void) { apiClient.request(api: .userInfo) { result in completion(result) } } func rxRequest() -> Observable<ResponseType> { return apiClient.rxRequest(api: .userInfo) } }
  11. rxRequestButton.rx.tap .do(onNext: { _ in self.label.text = "loading..." }) .flatMap

    { self.userInfoModel.rxRequest() } .flatMap { self.repositoryListModel.rxRequest(userId: $0.userId) } .map { $0.map { $0.title }.joined(separator: "\n") } .catchErrorJustReturn("Τϥʔ") .bind(to: self.label.rx.text) .disposed(by: disposeBag)