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
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
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.7k
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
250
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
180
Agentic UI
manfredsteyer
PRO
0
160
AIとASP.NET Coreで雑Webアプリを作った話
mayuki
0
630
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
180
OSもどきOS
arkw
0
570
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
240
3Dシーンの圧縮
fadis
1
770
A2UI という光を覗いてみる
satohjohn
1
140
JavaDoc 再入門
nagise
1
350
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
780
Featured
See All Featured
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.7k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
220
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
410
A Soul's Torment
seathinner
6
2.9k
How to train your dragon (web standard)
notwaldorf
97
6.7k
Believing is Seeing
oripsolob
1
150
Amusing Abliteration
ianozsvald
1
200
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
470
Building an army of robots
kneath
306
46k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
250
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
610
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
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ΞϓϦΤϯδχΞΛืूͯ͠·͢ʂ