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
VIPERアーキテクチャ
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Ryoichi Izumita
November 17, 2016
Programming
850
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
VIPERアーキテクチャ
第5回スタートアップiOS勉強会での発表資料
Ryoichi Izumita
November 17, 2016
More Decks by Ryoichi Izumita
See All by Ryoichi Izumita
モバイル開発における共通性・可変性分析入門
rizumita
0
100
Flutterアプリを生成AIで生成する勘所
rizumita
0
1.5k
FlutterアプリのテストでBuilderパターンを活用しよう
rizumita
0
770
SwiftUIの大地を駆け巡るための仕組みを作る
rizumita
0
280
FRPを使いはじめて3年が過ぎました。
rizumita
4
1.5k
とあるプログラマのリモートワーク
rizumita
0
400
JavaScript for Automation
rizumita
1
280
Other Decks in Programming
See All in Programming
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
1
210
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
200
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
530
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
0
120
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
190
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
1
270
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
550
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
140
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
480
Google Apps Script で Ruby を動かす
kawahara
0
130
言葉の格闘技のススメ~紙とペンと言葉から始める、キャリアの描き方~
progresscicada
1
120
今さら聞けない .NET CLI
htkym
0
180
Featured
See All Featured
Measuring & Analyzing Core Web Vitals
bluesmoon
9
950
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
270
How to make the Groovebox
asonas
2
2.3k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
230
Fireside Chat
paigeccino
42
4k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
420
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.7k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
920
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
What does AI have to do with Human Rights?
axbom
PRO
1
2.3k
Documentation Writing (for coders)
carmenintech
77
5.4k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
190
Transcript
VIPERΞʔΩςΫνϟ גࣜձࣾLang-8 @rizumita / ઘా ྖҰ
ࣗݾհ • ઘా ྖҰ • @rizumita • גࣜձࣾLang-8ͰiOSΞϓϦ։ ൃΛ୲ •
HiNative for iOS • εϓϥτΡʔϯͰͷ༻ϒΩ γϟʔϓϚʔΧʔωΦͱόϨϧ εϐφʔσί
HiNative • ݴޠࠃʹ͍ͭͯ؆୯ʹ࣭ Ͱ͖Δɻ • iOS / Android / Web
• https://hinative.com
ຊʹೖΓ·͢
AppleతMVC from developer.apple.com
iOSΞϓϦʹ͓͚Δ MVCͷ • ViewͱModel͕࿈ܞ͍ͯ͠ͳ͍ • ControllerʹΞϓϦέʔγϣϯϩδοΫ͕ूத • Controllerʹ͓͚Δը໘ભҠͰଞͷControllerʹґଘ
iOSʹ͓͚ΔMVVM • AppleతMVCʹ͓͚ΔViewͱModel͕࿈ܞ͠ͳ͍Λ ղܾ • ModelϨΠϠʔͷઃܭنఆ͞Ε͍ͯͳ͍ • ભҠϩδοΫͷ୲͕ෆ໌
VIPER • Clean ArchitectureͷҰछʢͩͱࢥ͏ʣ • MVC/MVVMͳͲͷΛղܾ • Router(Wireframe)͕ભҠϩδοΫΛ୲ • VIPER
≒ MVVM + Router (+ Interactor) • Interactor͕ϏδωεϩδοΫΛ୲ • MVVM(FRP)Redux(ReSwift)ϥΠϒϥϦʹґଘ͢Δ͕VIPERґଘ͠ͳ͍ • FRPΛར༻͢Δ߹ͱൺͯελοΫτϨʔε͕͔Γ͍͢ • ςετ͍͢͠ • ֤ϨΠϠʔؒͷଓDIΛ͏ͱྑ͍ • ϑΝΠϧ͕ଟ͘ͳΓ͕ͪ • Segueͷར༻ۤख
ద༻ • VIPERϨΠϠʔΛ5ͭʹ ͚ΔͷͰখ͍͞ΞϓϦ ͩͱ࣮͕໘ɻ • ෳࡶ͘͠ظϓϩδΣ Ϋτʹద͢Δɻ ظ ظ
୯७ × ◦ ෳࡶ ◦ ˕
ߏ View Router (Wireframe) Presenter Interactor Entity Ϣʔβ ΞΫγϣϯ ߋ৽
͍߹Θͤ ௨
class TaskListWireframe { weak var presentedViewController: UIViewController? func presentViewController(navigationController: UINavigationController)
{ let controller = TaskListViewController(nibName: nil, bundle: nil) let presenter = TaskListPresenter() let interactor = TaskListInteractor() let dataManager = TaskListDataManager() controller.eventHandler = presenter presenter.userInterface = controller presenter.input = interactor interactor.output = presenter interactor.dataManager = dataManager presentedViewController = controller navigationController.pushViewController(controller, animated: true) } } )ҰൠతʹDIΛߦ͍·͢
protocol TaskListViewProtocol: class { func show(tasks: [DisplayTask]) func show(errorMessage: String)
} extension TaskListViewController: TaskListViewProtocol { func show(tasks: [DisplayTask]) { self.tasks = tasks tableView.reloadData() } func show(errorMessage: String) { // errorMessageΛදࣔ } } class TaskListViewController: UITableViewController { var eventHandler: TaskListModuleProtocol? fileprivate var tasks: [DisplayTask] = [] override func viewDidLoad() { super.viewDidLoad() // লུ eventHandler?.updateView() } // UITableViewDataSourceলུ }
extension TaskListPresenter: TaskListModuleProtocol { func updateView() { input?.findTasks() } }
extension TaskListPresenter: TaskListInteractorOutputProtocol { func found(tasks: [Task]) { userInterface?.show(tasks: tasks.map(translate(task:))) } func occurred(error: AppError) { userInterface?.show(errorMessage: translate(error: error)) } } class TaskListPresenter { weak var userInterface: TaskListViewProtocol? var input: TaskListInteractorInputProtocol? } protocol TaskListModuleProtocol { func updateView() } protocol TaskListInteractorOutputProtocol: class { func found(tasks: [Task]) func occurred(error: AppError) }
protocol TaskListInteractorInputProtocol { func findTasks() } class TaskListInteractor: TaskListInteractorInputProtocol {
weak var output: TaskListInteractorOutputProtocol? var dataManager: TaskListDataManagerProtocol? func findTasks() { dataManager?.findTasks { [weak self] tasks, error in if let error = error { self?.output?.occurred(error: error) } else { self?.output?.found(tasks: tasks) } } } }
protocol TaskListDataManagerProtocol { func findTasks(completion: ([Task], AppError?) -> ()) }
class TaskListDataManager: TaskListDataManagerProtocol { func findTasks(completion: ([Task], AppError?) -> ()) { completion([Task(title: "First"), Task(title: "Second")], nil) } }
struct Task { let title: String } struct DisplayTask {
let title: String }
ભҠͷॻ͖ํ
class AddTaskWireframe { func presentAddTaskViewController(parent: UIViewController) { // ભҠίʔυ }
} protocol TaskListWireframeProtocol { func presentAddInterface() } extension TaskListWireframe: TaskListWireframeProtocol { func presentAddInterface() { guard let controller = presentedViewController else { return } addTaskWireframe?.presentAddTaskViewController(parent: controller) } } class TaskListPresenter { var wireframe: TaskListWireframeProtocol? // লུ… } extension TaskListPresenter: TaskListModuleProtocol { func addNewTask() { wireframe?.presentAddInterface() } // লུ… }
ςετͷॻ͖ํ
class TaskListPresenterTests: XCTestCase { class UserInterface: TaskListViewProtocol { var calledShowTasks
= false func show(tasks: [DisplayTask]) { calledShowTasks = true } var calledShowErrorMessage = false func show(errorMessage: String) { calledShowErrorMessage = true } } class Input: TaskListInteractorInputProtocol { var calledFindTasks = false func findTasks() { calledFindTasks = true } } func testUpdateView() { let presenter = TaskListPresenter() let userInterface = UserInterface() let input = Input() presenter.userInterface = userInterface presenter.input = input presenter.updateView() XCTAssertTrue(input.calledFindTasks) } }
ٻਓࠂ • iOSΞϓϦΤϯδχΞΛืूͯ͠·͢ʂ