Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
VIPER
Search
lcr3
December 10, 2020
Programming
110
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
VIPER
VIPERの仕様をまとめました
lcr3
December 10, 2020
More Decks by lcr3
See All by lcr3
XCUITest by PageObjectPattern
lcr3
0
57
アプリエンジニアになるには
lcr3
0
40
Other Decks in Programming
See All in Programming
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
290
自サークルのIdPからログアウトできるようになるまで
taiseiue
1
140
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
610
AmebaブログはKMPから卒業します
kmars0605
0
180
最近”作らせてる” ローカルAIアプリの話
akit37
0
470
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
220
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1.2k
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
15
8.5k
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
180
[ハンズオン]AIへの指示だけで「五目並べ」を作ってみよう
satoshi256kbyte
1
380
FactoryBotをやめればRSpecは速くなるのか?
yuta_onishi_97
0
270
Featured
See All Featured
First, design no harm
axbom
PRO
2
1.3k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
480
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.7k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
540
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Docker and Python
trallard
47
4.2k
Into the Great Unknown - MozCon
thekraken
41
2.8k
Practical Orchestrator
shlominoach
192
12k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
2
410
Building the Perfect Custom Keyboard
takai
2
910
Transcript
VIPER
VIPERͱ • iOS༻ʹੜ·ΕͨΞʔΩςΫνϟ • ӈهͷ5ͭͷཁૉͰߏ͞ΕΔ
ΞʔΩςΫνϟͷཧ೦ • ୯Ұͷݪଇ • ProtocolΛͬͯͦΕʹ४ڌ࣮ͨ͠Λߦ͏ • ཁૉؒͷΓͱΓProtocolΛհͯ͠ΞΫηε͢Δ
View UIViewController Presenter Router Interactor Entity Ϣʔβʔ͔Βͷ ΞΫγϣϯ ViewͷΞοϓσʔτ σʔλऔಘΛґཔ
औಘͨ͠σʔλ[Entity] औಘͨ͠σʔλΛύʔε ը໘ભҠΛґཔ
Router protocol WeatherListWireframe { func showWeatherDetail(forecasts: [Forcast]) } class WeatherListRouter
{ private unowned let viewController: UIViewController init(viewController: UIViewController) { self.viewController = viewController } // DI static func assembleModules() -> UIViewController { let view = WeatherListViewController.instantiate() let router = WeatherListRouter(viewController: view) let interector = WeatherListInteractor() let presenter = WeatherListPresenter(view: view, interactor: interector, router: router) view.presenter = presenter // ViewʹPresenterΛઃఆ return view } } extension WeatherListRouter: WeatherListWireframe { // Protocolʹ४ڌ func showWeatherDetail(forecasts: [Forcast]) { let weatherDetailView = WeatherDetailRouter.assembleModules(forecasts: forecasts) viewController.navigationController?.present(weatherDetailView, animated: true) } } • ʮը໘ભҠʯͱʮDIʯΛ୲
View • Viewͷߋ৽ • ϢʔβʔͷΠϕϯτ௨ protocol WeatherListView: AnyObject { func
showWeatherData(weathers: [WeatherEntity]) func showErrorAletView(errorMessage: String) var presenter: WeatherListPresentation! { get } } class WeatherListViewController: UIViewController { var presenter: WeatherListPresentation! var weathers: [WeatherEntity] @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() // Presenterʹσʔλऔಘґཔ presenter.viewDidLoad() } } extension WeatherListViewController: WeatherListView { // Presenter͔Βσʔλऔಘޭ௨ func showWeatherData(weathers: [WeatherEntity]) { weathers = weathers tableView.reloadData() } // Presenter͔Βσʔλऔಘࣦഊ௨ func showErrorAletView(errorMessage: String) { // ΤϥʔΞϥʔτදࣔॲཧ } } extension WeatherListViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // Presenterʹηϧ͕λοϓ͞Εͨ௨ΛૹΔ let index = indexPath.row presenter.weatherListCellTouched(forecasts: weathers[index].forecasts) } }
Presenter • View͔Βड͚औͬͨΠϕϯτΛݩʹґཔ protocol WeatherListPresentation { func viewDidLoad() func weatherListCellTouched(forecasts:
[Forcast]) } class WeatherListPresenter { private weak var view: WeatherListView? private let router: WeatherListWireframe private let interactor: WeatherListUsecase // RouterͰDI͢Δͱ͖ʹ༻͢Δ init(view: WeatherListView, interactor: WeatherListUsecase, router: WeatherListWireframe) { self.view = view self.interactor = interactor self.router = router } } extension WeatherListPresenter: WeatherListPresentation { func viewDidLoad() { // InteractorʹఱؾͷใͷऔಘΛґཔ interactor.getWeatherList() { [weak self] result in switch result { case .success(let weathers): // ViewʹσʔλऔಘޭΛ௨ view?.showWeatherData(weathers: weathers) case .failure: // ViewʹσʔλऔಘࣦഊΛ௨ view?.showErrorAlert(errorMessage: "औಘʹࣦഊ͠·ͨ͠ɻ") } } } func weatherListCellTouched(forecasts: [Forcast]) { // Routerʹৄࡉը໘ͷભҠΛґཔ router.showWeatherDetail(forecasts: forecasts) } } import UIKit
Interactor • APIͷΓͱΓΛ୲ protocol WeatherListUsecase { func getWeatherList(completion: @escaping (Result<[WeatherEntity],
Error>) -> Void) } class WeatherListInteractor { private let client: APIRequestable // MockΛࠩ͠ସ͑ΕΔΑ͏ʹ͓ͯ͘͠ init(client: APIRequestable = APIClient()) { self.client = client } } extension WeatherListInteractor: WeatherListUsecase { func getWeatherList(completion: @escaping (Result<[WeatherEntity], Error>) -> Void) { let request = WeatherAPI.getWeatherList() client.send(request: request) { result in completion(result) } } }
Entity • σʔλߏͷఆٛ • ϩδοΫΛ࣋ͨͳ͍Α͏ʹ͢Δ struct WeatherEntity: Codable { var
title: String var link: String var location: Location var forecasts: [Forcast] }
୯ମςετ • ςετର͕ґଘ͍ͯ͠ΔΫϥεͷMockΛ࡞ • ςετ͍ͨ͠ରͷϝιουΛݺͼग़ͯ͠ class WeatherListPresenterTests: XCTestCase { //
ґଘ͢ΔΫϥεͷॳظԽ let view = MockWeatherListView() let interactor = MockWeatherListInteractor() let router = MockWeatherListRouter() var presenter: WeatherListPresenter! override func setUpWithError() throws { super.setUp() // DI presenter = WeatherListPresenter(view: view, interactor: interactor, router: router) view.presenter = presenter } func testViewDidLoad() { // presenterͷviewDidLoadΛґཔ͞Εͨͱ͖ presenter.viewDidLoad() // interactorʹσʔλऔಘ͕ґཔ͞Ε͍ͯΔ͜ͱ XCTAssertEqual(interactor.callCountGetLocations, 1) }
σϝϦοτ • ϑΝΠϧ͕ଟ͍
·ͱΊ • ୯ҰͷݪଇΛͱʹదʹΫϥεׂ͢Δ • ը໘ੜ Router Ͱߦ͍ɺΫϥε෦Ͱ init() Λ͠ͳ͍ •
ׂ͞ΕͨͦΕͧΕͷΫϥεprotocolΛհͯ͠ΞΫηε͢Δ͜ͱ • View ͱ Router Ҏ֎ import UIKit ېࢭ • MockΛͬͯςετରʹඞཁͳΫϥεͳͲΛࠩ͠ସ͑Δ͜ͱͰUnitςετՄ ೳ •