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

Moya+RxSwiftで実現する!ReactiveなAPIリクエスト

F05557f473bac91b5bdc6c2e8a95c6f2?s=47 satoshin21
October 02, 2017

 Moya+RxSwiftで実現する!ReactiveなAPIリクエスト

俺コン Vol.1 / Day. 1
https://orecon.connpass.com/event/63769/

F05557f473bac91b5bdc6c2e8a95c6f2?s=128

satoshin21

October 02, 2017
Tweet

Transcript

  1. Moya + RxSwi,Ͱ࣮ݱ͢Δʂ Reac%veͳAPIϦΫΤετ Զίϯ Vol.1 Day. 1 @satoshin21 @satoshin21

    1
  2. INTRODUCE • @satoshin21 • eureka, Inc. • Pairs JP iOS

    Applica<on Engineer • created Chainable Anima<on Library "Anima" @satoshin21 2
  3. @satoshin21 3

  4. What's Moya? @satoshin21 4

  5. Whats' Moya? • Network abstrac.on layer • RxSwi6, Reac.veSwi6ͱͷ࿈ܞ͕σϑΥϧτͰՄೳ •

    encapsulates Alamofire • ϓϥάΠϯΛ࡞੒Մೳ • ίϛϡχςΟ͕׆ൃ ( ༷ʑͳExtension ) @satoshin21 5
  6. How to implement Moya.TargetType public enum GitHub { case zen

    case userProfile(String) case userRepositories(String) } @satoshin21 6
  7. How to implement Moya.TargetType extension GitHub: TargetType { public var

    baseURL: URL { return URL(string: "https://api.github.com")! } public var path: String { switch self { case .userProfile(let name): return "/users/\(name.urlEscaped)" ... } } public var method: Moya.Method = .get public var parameters: [String: Any]? { ... } } @satoshin21 7
  8. How to request with RxSwi0 & Moya let githubProvider =

    MoyaProvider<GitHub>() githubProvider.request(.userProfile("satoshin21")).subscribe { event in switch event { case let .next(response): let jsonString = try? response.mapString() message = jsonString ?? message case let .error(error): print(error) default: break } } @satoshin21 8
  9. @satoshin21 9

  10. That's it? @satoshin21 10

  11. Sampleͷ՝୊ • enumʹTargetTypeΛ࣮૷ • ΤϯυϙΠϯτ͕૿͑Δͱ஍ࠈ • Observable<Moya.Response> • Response ParseΛຖ౓ߦ͏

    • APIKitͷΑ͏ʹType SafeͰ͸ͳ͍ @satoshin21 11
  12. ཧ૝ܗ DoSomething() .asDriver(onErrorJustReturn: nil) .drive(imageView.rx.image) .addDisposableTo(disposeBag) @satoshin21 12

  13. Moya Customiza-on for Pairs(jp) • enum to struct • Type

    safeͳObservable<E> • Type Erasure @satoshin21 13
  14. @satoshin21 14

  15. enum to struct enum API { } extension API {

    enum Community {} } // Community API extension API.Community { /// ίϛϡχςΟ৘ใऔಘ struct GetSingle: PairsTargetType { ... } /// Search struct Search: PairsTargetType { ... } } @satoshin21 15
  16. enum to struct let communitySearch = API.Community.Search() @satoshin21 16

  17. PairsTargetType protocol PairsTargetType: TargetType, ObservableType { /// DecodedResponseType associatedtype D

    /// ObservableType.EʹόΠϯυͤ͞ΔͨΊ associatedtype E /// Ϩεϙϯε͔ΒೝΊ͍ͯΔܗࣜ΁σίʔυ͢ΔʢJSONͳͲʣ func decodeResponse(_ response: Moya.Response) throws -> D /// Ϩεϙϯε৘ใ͔Β׬ྃ·ͰͷObservableΛ࡞੒͢Δ func didDecodeData(_ responseData: D) -> Observable<E> } @satoshin21 17
  18. implements PairsTargetType struct GetCampaign: PairsTargetType { // Moya.Response -> JSON

    typealias D = JSON // JSON -> [Community] typealias E = [Community] func didDecodeData(_ responseData: JSON) -> Observable<[Community]> { // JSON͔Β[Community]΁ͷϚοϐϯά΍DBͷอଘͳͲ let communities = ... return communities } } @satoshin21 18
  19. PairsTargetTypeͷObservableԽ extension PairsTargetType { func subscribe<O: ObserverType>(_ observer: O) ->

    Disposable where O.E == E { // APIϦΫΤετ -> decodeResponse(response)ͰMoya.Response͔Βσίʔυ let requestData = Observable<D>.create { (observer) in let cancellable = API.provider.request(.init(target: self), completion: { (result) in switch result { case .success(let response): let responseData = try self.decodeResponse(response) observer.onNext(responseData) observer.onCompleted() } ) return Disposables.create(with: cancellable.cancel) } // σίʔυ͞ΕͨΦϒδΣΫτ(ओʹJSON)͔ΒϚοϐϯά͞ΕͨΦϒδΣΫτ΁ return requestData .flatMap(self.didDecodeData) .subscribe(observer) } @satoshin21 19
  20. RxMoyaProvider<AnyPairsTarget> extension API { fileprivate static let provider = API.Provider()

    // PairsTargetTypeΛ࣮૷ͨ͠ϦΫΤετͷॲཧΛߦ͏ fileprivate class Provider: RxMoyaProvider<AnyPairsTarget> { init() { } } } @satoshin21 20
  21. Binding API.Image.Get() .asDriver(onErrorJustReturn: nil) .drive(imageView.rx.image) .addDisposableTo(disposeBag) @satoshin21 21

  22. How we use Moya in Pairs // ίϛϡχςΟͱΧςΰϦʔΛऔಘ Observable .zip(

    API.Community.GetCommunities(), API.Community.GetCategories(), resultSelector: { $0 }) .subscribe( onNext: { (communities: [Community], categories: [Category]) in // do something! }).addDisposableTo(disposeBag) @satoshin21 22
  23. Summary • Moyaࣗମ΋ڧྗ͕ͩɺΧελϚΠζͰΑΓReac)veʹ @satoshin21 23

  24. @satoshin21 24