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
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
110
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
270
PHP Application における Kubernetes 内 gRPC 通信
ganchiku
0
560
Lean は証明の正しさを確認するためだけのツールって思ってませんか?
inoueasei
1
120
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.4k
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
9
5.8k
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
180
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
130
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
0
110
FDEが実現するAI駆動経営の現在地
gonta
2
240
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
150
AI時代、エンジニアはどう育つのか -未経験エンジニアの成長を間近で見て考えたこと-
thasu0123
0
200
Featured
See All Featured
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
270
Building an army of robots
kneath
306
46k
Scaling GitHub
holman
464
140k
Utilizing Notion as your number one productivity tool
mfonobong
4
480
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.1k
Music & Morning Musume
bryan
47
7.3k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
190
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
400
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.7k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
The Invisible Side of Design
smashingmag
301
52k
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