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
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
110
Flutterアプリを生成AIで生成する勘所
rizumita
0
1.6k
FlutterアプリのテストでBuilderパターンを活用しよう
rizumita
0
790
SwiftUIの大地を駆け巡るための仕組みを作る
rizumita
0
290
FRPを使いはじめて3年が過ぎました。
rizumita
4
1.5k
とあるプログラマのリモートワーク
rizumita
0
400
JavaScript for Automation
rizumita
1
290
Other Decks in Programming
See All in Programming
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
170
Security issues being discussed on Web Platforms
petamoriken
0
710
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
120
ソフトウェアラスタライザ
fadis
1
800
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
4
1.1k
Heart of Swift Concurrency
koher
0
220
アクセシビリティから考える情報設計
high_g_engineer
0
350
巨大モノリシックアプリ モダン化大作戦
ktcryomm
0
790
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
130
業務時間外もAIに働いてもらう話
colorful12
3
10k
高専キャリア LT 発表内容
crysta1221
6
5.6k
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
490
Featured
See All Featured
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
340
What's in a price? How to price your products and services
michaelherold
247
13k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
880
A Modern Web Designer's Workflow
chriscoyier
699
190k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
What does AI have to do with Human Rights?
axbom
PRO
1
2.4k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
430
Visualization
eitanlees
152
17k
Mobile First: as difficult as doing things right
swwweet
225
10k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
240
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
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ΞϓϦΤϯδχΞΛืूͯ͠·͢ʂ