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

Clean Swift

Clean Swift

iOSでクリーンアーキテクチャー

63734ceb95277fe45a25988f653e7e8f?s=128

Yoann Coldefy

October 01, 2016
Tweet

More Decks by Yoann Coldefy

Other Decks in Programming

Transcript

  1. Clean Swift

  2. ࣗݾ঺հ • ໊લɿίʔυώʔϤΞϯ • ग़਎ɿGrenoble • ৬ۀɿιϑτΤΞʔΤϯδχΞʔ • ։ൃܦݧɿDelphiʢ7೥ʣɺSwiftʢ൒೥ʣ •

    Facebookɿhttps://www.facebook.com/yoann.coldefy • Twitterɿ@luinily
  3. • View Controller͸େ͖͘ͳΔ • View Controller͕ෳࡶʹͳΔ • อक͠ʹ͍͘ • ࢓༷มߋʹରԠ͠ʹ͍͘

  4. • ΫϦʔϯߏ૝ • ੹೚Λ෼͚Δ • ґଘΛੵۃతʹ཈͑Δ

  5. • ୯ମςετ • ςετۦಈͰࣗવʹมߋ͠΍͍͢ߏங • ϦϑΝΫτϦϯάͯ͠΋҆৺

  6. iOSͰ͸Ͳ͏͢Ε͹͍͍ʁ

  7. View Controller Interactor Presenter VIP cycle

  8. View Controller Interactor Presenter VIP cycle Viewͷίϯτϩʔϧ

  9. View Controller Interactor Presenter VIP cycle Ϟσϧͱͷ΍ΓͱΓ

  10. View Controller Interactor Presenter VIP cycle දࣔ༻ͷσʔλΛ੔ܗ

  11. View Controller Interactor Presenter VIP cycle

  12. Input protocol Output
 protocol Data Data Data Data

  13. View Controller View Model Request View

  14. class ApodViewController: UIViewController { var output: ApodViewControllerOutput! }

  15. class ApodViewControllerTests { override func setUp() { super.setUp() window =

    UIWindow() setupApodViewController() outputSpy = MockApodViewControllerOutput() target.output = outputSpy } func test_viewDidLoad_fetchTodaysApodIsCalled() { // Arrange // Act loadView() // Assert XCTAssertTrue(outputSpy.fetchTodayApodCalled) } }
  16. class ApodViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() fetchTodaysApod()

    } func fetchTodaysApod() { let request = TodayApodRequest() output.fetchTodayApod(request: request) } }
  17. Interactor Worker Worker Worker Request Response Business Logic

  18. 
 class ApodInteractor: ApodInteractorInput { var output: ApodInteractorOutput! private var

    _apodWorker: ApodWorker }
  19. 
 func test_fetchTodayApod_callsApodWorkerFetchTodayApod() { // Arrange let request = TodayApodRequest()

    // Act target.fetchTodayApod(request: request) // Assert XCTAssertTrue(mochApodWorker.fetchTodayApodCalled) } func test_fetchTodayApod_callsOutputPresentApod() { // Arrange let request = TodayApodRequest() // Act target.fetchTodayApod(request: request) // Assert XCTAssertTrue(mochOutput.presentOutputCalled) }
  20. 
 class ApodInteractor: ApodInteractorInput { func fetchTodayApod(request: TodayApodRequest) { _apodWorker.fetchTodayAPOD()

    { apodData, error in let response = ApodResponse(apodData: apodData) self.output.presentApod(response: response) } } }
  21. Presenter Response View Model

  22. 
 class ApodPresenter: ApodPresenterInput { weak var output: ApodPresenterOutput! }

  23. 
 func test_presentApod_callsDisplayAPOD() func test_presentApod_viewModelContainsTitle() func test_presentApod_viewModelContainsFormatedDate() { {…} //

    Assert XCTAssertEqual(mockOutput.apodViewModel?.date, "2016೥07݄18೔") }
  24. 
 class ApodPresenter: ApodPresenterInput { func presentApod(response: ApodResponse) { let

    apodViewModel = makeApodViewModel(apodData: response.apodData) output.displayApod(viewModel: apodViewModel) } private func makeApodViewModel(apodData: ApodData) -> ApodDataViewModel { let title = apodData.title let date = dateToString(date: apodData.date) let explanation = apodData.explanation let copyright = apodData.copyright return ApodDataViewModel(title: title, date: date, explanation: explanation, copyright: copyright) } }
  25. View Controller View Model Request View

  26. 
 func test_displayApod_TitleIsDisplayed() { // Arrange loadView() let viewModel =

    prepareViewModel() // Act target.displayApod(viewModel: viewModel) // Assert XCTAssertEqual(target.titleLabel.text, viewModel.title) }
  27. 
 extension ApodViewController: ApodViewControllerInput { func displayApod(viewModel: ApodDataViewModel) { titleLabel.text

    = viewModel.title explanationTextView.text = viewModel.explanation } }
  28. • InteractorɺPresenterͳͲͷઃఆͱ݁ͼ͚ͭ class ApodConfigurator { func configure(viewController: ApodViewController) { let

    router = ApodRouter() router.viewController = viewController let presenter = ApodPresenter() presenter.output = viewController let interactor = configureInteractor(presenter: presenter) viewController.output = interactor viewController.router = router } }
  29. 
 protocol ApodViewControllerOutput { func fetchTodayApod(request: TodayApodRequest) func fetchRandomApod(request: RandomApodRequest)

    } protocol ApodInteractorInput { func fetchTodayApod(request: TodayApodRequest) func fetchRandomApod(request: RandomApodRequest) }
  30. 
 extension ApodInteractor: ApodViewControllerOutput { }

  31. ·ͱΊ • ςετۦಈ։ൃ͕Ͱ͖Δ • σΟάϨʔυ͠ʹ͍͘ • ֤Ϋϥεͷ੹೚͕͸͖ͬΓ͍ͯ͠ΔͷͰɺό άमਖ਼΍มߋ͕͠΍͍͢

  32. • Ϋϥεؒͷґଘੑ͕௿͍ͨΊɺผͷΫϥ ε͕ೖΓม͑΍͍͢ • View Controller͸Ϗϡʔͷ੍ޚͱೖྗؔ܎ ͷίʔυ͔͠ͳ͍

  33. • ίʔυ͕݁ߏ૿͑ͯ͠·͍·͢ • ςετॻ͘ͷͰɺඞཁ࣌ؒ΋૿͑·͢ • ࠷ॳ͸ϋʔυϧ͕ͪΐͬͱߴΊ

  34. http://clean-swift.com https://github.com/luinily/spaceApp http://qiita.com/takahia/items/67b9e1229682127d924e