Slide 1

Slide 1 text

Layered Architectureʹ͓͚Δ RxSwiftΛ༻͍ͨErrorͷ఻ൖ Kyobashi.swift Recruit Marketing Partners

Slide 2

Slide 2 text

ࣗݾ঺հ • Takeshi Ihara / @nonchalant0303 • Recruit Marketing Partners • iOS Engineer

Slide 3

Slide 3 text

RxSwiftʹContribute͠·ͨ͠

Slide 4

Slide 4 text

Layered Architecture *OGSB 1SFTFOUBUJPO %PNBJO

Slide 5

Slide 5 text

Layered Architecture *OGSB "1*3FRVFTU %# 1SFTFOUBUJPO 6* %PNBJO ϏδωεϩδοΫ

Slide 6

Slide 6 text

Error *OGSB 1SFTFOUBUJPO %PNBJO $POOFDUJPO 6OBVUIPSJ[FE 4FSWFS&SSPS -PHJD 5SBOTMBUJPO

Slide 7

Slide 7 text

*OGSB 1SFTFOUBUJPO %PNBJO $POOFDUJPO 4FSWFS&SSPS -PHJD 5SBOTMBUJPO 6OBVUIPSJ[FE "MFSU'BMMCBDL "MFSU3FUSZ Each Error, Each Process

Slide 8

Slide 8 text

͜ͷ֤૚ͷErrorΛͲ͏΍ͬͯ RxSwiftΛ࢖ͬͯ ϋϯυϦϯά͢Δ͔͕ࠓճͷ࿩

Slide 9

Slide 9 text

RxSwift Rx is a generic abstraction of computation expressed through Observable interface. This is a Swift version of Rx.

Slide 10

Slide 10 text

class ViewController: UIViewController { … override func viewDidLoad() { super.viewDidLoad() presenter.prepare() .subscribe( onNext: { domainModel in // Viewʹ൓ө }, onError: { error in // Τϥʔॲཧ } ) .addDisposableTo(disposeBag) } } subscribe - onError Ͳ͜Ͱى͖ͨΤϥʔ͔෼͔Βͳ͍ʜ

Slide 11

Slide 11 text

·ͣ͸

Slide 12

Slide 12 text

֤૚ͷΤϥʔΛఆٛ [Infra] enum InfrastructureError: Error { case connection case anthorization } extension InfrastructureError { static func create(error: Error) -> InfrastructureError { ... return infraError } }

Slide 13

Slide 13 text

֤૚ͷΤϥʔΛఆٛ [Domain] enum DomainError: Error { case logic case translation } extension DomainError { static func create(error: Error) -> DomainError { ... return domainError } }

Slide 14

Slide 14 text

֤૚ͷΤϥʔΛఆٛ [Presentation] enum PresentationError: Error { case connection case unknown }

Slide 15

Slide 15 text

Layered Architecture x RxSwift *OGSB 1SFTFOUBUJPO %PNBJO 0CTFSWBCMF&OUJUZ 0CTFSWBCMF%PNBJO.PEFM "1*3FRVFTU &WFOU 7JFXʹ൓ө

Slide 16

Slide 16 text

Layered Architecture x RxSwift *OGSB 1SFTFOUBUJPO %PNBJO 0CTFSWBCMF&OUJUZ 0CTFSWBCMF%PNBJO.PEFM "1*3FRVFTU &WFOU 7JFXʹ൓ө *OGSB&SSPS %PNBJO&SSPS

Slide 17

Slide 17 text

public static func error(_ error: Swift.Error) -> Observable { return ErrorProducer(error: error) } Observable.error ObservableType.catchError public func catchError(_ handler: @escaping (Error) throws -> RxSwift.Observable) -> RxSwift.Observable 0CTFSWBCMFʹแΜͩΤϥʔΛੜ੒͢Δ 0CTFSWBCMFͷதͰൃੜͨ͠ΤϥʔΛ $BUDIͯ͠ճ෮ॲཧΛ͢Δ

Slide 18

Slide 18 text

protocol Repository { func find() -> Observable } struct RepositoryImpl: Repository { … func find() -> Observable { return apiClient.send() .catchError { return Observable.error(InfrastructureError.create(error: $0)) } } } %PNBJO૚ʹެ։͢Δ*OUFSGBDF ͜͜Ͱ"1*͔Βฦ͖ͬͯͨ&SSPSΛ *OGSB&SSPSʹม׵͍ͯ͠Δ *OGSB

Slide 19

Slide 19 text

struct Translator { static func translate(entity: Entity) throws -> DomainModel { ... throw DomainError.translation ... return domainModel } } protocol UseCase { func prepare() -> Observable } struct UseCaseImpl: UseCase { … func prepare() -> Observable { return repository.find() .map { try Translator.translate(entity: $0) } } } NBQͰUISPX͞ΕͨΒ 0CTFSWBCMFFSSPSʹͳΔ %PNBJO

Slide 20

Slide 20 text

struct Presenter { … func prepare() -> Observable { return useCase.prepare() .catchError { error in guard let infraError = error as? InfrastructureError else { return Observable.error(PresentationError.unknown) } switch infraError { case .connection: return Observable.error(PresentationError.connection) default: return Observable.error(PresentationError.unknown) } } } } 1SFTFOUBUJPO ಛఆͷ&SSPSܕͷͱ͖ʹ ಛผͳΤϥʔΛฦ͢

Slide 21

Slide 21 text

͋ͱ͸PresentationErrorͷܕ ΛݟͯݸผͷॲཧΛ͢Ε͹

Slide 22

Slide 22 text

*OGSB 1SFTFOUBUJPO %PNBJO $POOFDUJPO 4FSWFS&SSPS -PHJD 5SBOTMBUJPO 6OBVUIPSJ[FE "MFSU'BMMCBDL "MFSU3FUSZ Each Error, Each Process

Slide 23

Slide 23 text

·ͱΊ • Layered Architecture x RxSwiftͷΤϥʔ఻ ൖʹ͍ͭͯͷҰྫΛߟ͑ͨ • catchError͸errorΛฦͣ͞ճ෮ॲཧ΋ॻ͚ ΔͷͰҟৗܥ͔Βਖ਼ৗܥʹ໭Δ͜ͱ΋Մೳ