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
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
760
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
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
260
技術記事、AIに書かせるか、自分で書くか? 〜それでも私が自分の手で書く理由〜 / #QiitaConference
jnchito
2
1.4k
Lessons from Spec-Driven Development
simas
PRO
0
200
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
790
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
130
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
120
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.1k
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
140
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.3k
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
560
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
130
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
120
Featured
See All Featured
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
300
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
840
Faster Mobile Websites
deanohume
310
31k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
310
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.1k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
190
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.5k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
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ΞϓϦΤϯδχΞΛืूͯ͠·͢ʂ