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
Ryoichi Izumita
November 17, 2016
Programming
840
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
390
JavaScript for Automation
rizumita
1
280
Other Decks in Programming
See All in Programming
PHP初心者セッション2026 〜生成AIでは見えない裏側を知る:今だからLAMPを通して仕組みを学ぶ〜
kashioka
0
620
act2-costs.pdf
sumedhbala
0
120
継続モナドとリアクティブプログラミング
yukikurage
3
620
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
150
Terraform標準の組織で AWS CDKをどう使うか
mu7889yoon
1
330
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
170
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
180
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
330
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.2k
初めてのKubernetes 本番運用でハマった話
oku053
0
130
型も通る、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
390
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
680
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
28
2.7k
Designing for Timeless Needs
cassininazir
1
390
Navigating Weather and Climate Data
rabernat
0
390
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
The untapped power of vector embeddings
frankvandijk
2
1.8k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
380
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
770
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
57k
Prompt Engineering for Job Search
mfonobong
0
380
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
660
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
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ΞϓϦΤϯδχΞΛืूͯ͠·͢ʂ