Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Clean Swift
Search
Yoann Coldefy
October 01, 2016
Programming
370
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Clean Swift
iOSでクリーンアーキテクチャー
Yoann Coldefy
October 01, 2016
More Decks by Yoann Coldefy
See All by Yoann Coldefy
ViewControllerの単体テスト
luinily
1
310
Other Decks in Programming
See All in Programming
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
270
typoなんかねぇよ
raspython3
0
340
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
350
Building a Meta Ray-Ban display app
akkeylab
0
170
メールのエイリアス機能を履き違えない
isshinfunada
0
250
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.1k
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
1.1k
今さら聞けない .NET CLI
htkym
0
210
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
140
Cloudflare is Agents
chimame
0
180
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
100
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
2
400
Featured
See All Featured
Fashionably flexible responsive web design (full day workshop)
malarkey
408
67k
Claude Code のすすめ
schroneko
67
230k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
680
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
220
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.5k
The browser strikes back
jonoalderson
0
1.5k
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Transcript
Clean Swift
ࣗݾհ • ໊લɿίʔυώʔϤΞϯ • ग़ɿGrenoble • ৬ۀɿιϑτΤΞʔΤϯδχΞʔ • ։ൃܦݧɿDelphiʢ7ʣɺSwiftʢʣ •
Facebookɿhttps://www.facebook.com/yoann.coldefy • Twitterɿ@luinily
• View Controllerେ͖͘ͳΔ • View Controller͕ෳࡶʹͳΔ • อक͠ʹ͍͘ • ༷มߋʹରԠ͠ʹ͍͘
• ΫϦʔϯߏ • Λ͚Δ • ґଘΛੵۃతʹ͑Δ
• ୯ମςετ • ςετۦಈͰࣗવʹมߋ͍͢͠ߏங • ϦϑΝΫτϦϯάͯ҆͠৺
iOSͰͲ͏͢Ε͍͍ʁ
View Controller Interactor Presenter VIP cycle
View Controller Interactor Presenter VIP cycle Viewͷίϯτϩʔϧ
View Controller Interactor Presenter VIP cycle ϞσϧͱͷΓͱΓ
View Controller Interactor Presenter VIP cycle දࣔ༻ͷσʔλΛܗ
View Controller Interactor Presenter VIP cycle
Input protocol Output protocol Data Data Data Data
View Controller View Model Request View
class ApodViewController: UIViewController { var output: ApodViewControllerOutput! }
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) } }
class ApodViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() fetchTodaysApod()
} func fetchTodaysApod() { let request = TodayApodRequest() output.fetchTodayApod(request: request) } }
Interactor Worker Worker Worker Request Response Business Logic
class ApodInteractor: ApodInteractorInput { var output: ApodInteractorOutput! private var
_apodWorker: ApodWorker }
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) }
class ApodInteractor: ApodInteractorInput { func fetchTodayApod(request: TodayApodRequest) { _apodWorker.fetchTodayAPOD()
{ apodData, error in let response = ApodResponse(apodData: apodData) self.output.presentApod(response: response) } } }
Presenter Response View Model
class ApodPresenter: ApodPresenterInput { weak var output: ApodPresenterOutput! }
func test_presentApod_callsDisplayAPOD() func test_presentApod_viewModelContainsTitle() func test_presentApod_viewModelContainsFormatedDate() { {…} //
Assert XCTAssertEqual(mockOutput.apodViewModel?.date, "201607݄18") }
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) } }
View Controller View Model Request View
func test_displayApod_TitleIsDisplayed() { // Arrange loadView() let viewModel =
prepareViewModel() // Act target.displayApod(viewModel: viewModel) // Assert XCTAssertEqual(target.titleLabel.text, viewModel.title) }
extension ApodViewController: ApodViewControllerInput { func displayApod(viewModel: ApodDataViewModel) { titleLabel.text
= viewModel.title explanationTextView.text = viewModel.explanation } }
• 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 } }
protocol ApodViewControllerOutput { func fetchTodayApod(request: TodayApodRequest) func fetchRandomApod(request: RandomApodRequest)
} protocol ApodInteractorInput { func fetchTodayApod(request: TodayApodRequest) func fetchRandomApod(request: RandomApodRequest) }
extension ApodInteractor: ApodViewControllerOutput { }
·ͱΊ • ςετۦಈ։ൃ͕Ͱ͖Δ • σΟάϨʔυ͠ʹ͍͘ • ֤Ϋϥεͷ͕͖ͬΓ͍ͯ͠ΔͷͰɺό άमਖ਼มߋ͕͍͢͠
• Ϋϥεؒͷґଘੑ͕͍ͨΊɺผͷΫϥ ε͕ೖΓม͍͑͢ • View ControllerϏϡʔͷ੍ޚͱೖྗؔ ͷίʔυ͔͠ͳ͍
• ίʔυ͕݁ߏ૿͑ͯ͠·͍·͢ • ςετॻ͘ͷͰɺඞཁ࣌ؒ૿͑·͢ • ࠷ॳϋʔυϧ͕ͪΐͬͱߴΊ
http://clean-swift.com https://github.com/luinily/spaceApp http://qiita.com/takahia/items/67b9e1229682127d924e