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
Clean Swift Workshop
Search
Chiaote Ni
November 08, 2020
Programming
830
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Clean Swift Workshop
Chiaote Ni
November 08, 2020
More Decks by Chiaote Ni
See All by Chiaote Ni
MCP - iPlayground
chiaoteni
0
140
Swift Testing - iPlayground
chiaoteni
0
310
Swift Package Manager
chiaoteni
0
160
Swift Smart KeyPath
chiaoteni
0
1.4k
Other Decks in Programming
See All in Programming
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
3
530
Intent as Code
shoppingjaws
6
940
What We Talk About When We Talk About XP
m_seki
2
500
AI駆動開発にグラフDBを重ねてみた
satoshi256kbyte
2
780
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
120
LLMは4年分のCompose移行を再現できるのか?実プロダクト279件のXMLで探る自動化の境界線
makun
0
550
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
240
Family mrubyの進捗
kishima
1
110
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
110
App Intentsのビルドプロセスを支える技術
kntkymt
0
260
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
0
180
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
300
Featured
See All Featured
Done Done
chrislema
186
16k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.8k
The Language of Interfaces
destraynor
162
27k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
830
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
730
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
Design in an AI World
tapps
1
310
Heart Work Chapter 1 - Part 1
lfama
PRO
9
36k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
500
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.1k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
820
Transcript
Clean Swift A better architecture to make project testable iOS@Taipei
艾倫 Ni & William Kuo
What is Clean Swift?
ViewController
Scene
Interactor Presenter ViewController
ViewController Interactor Presenter Display Logic Business Logic Presentation Logic ViewController
Interactor Presenter Display Logic Business Logic Presenta tion Logic
ViewControll Interact Presenter Display Logic Business Logic Presentation Logic Worker
Worker Worker
Worker ORM / DB Local API Network / API Network
API ViewControll Interact Presenter Display Logic Business Logic Presentation Logic
Worker ViewControll Interact Presenter Display Logic Business Logic Presentation Logic
I13N Calculate Thumbnail resize Parse video’s metadata
Interactor Presenter ViewController Request Response ViewModel
None
Boundary
viewContorller interactor presentor in out in out DisplayLogic in out
Boundary Boundary Boundary BusinessLogic Presentation Logic
protocol MeetupEventListDisplayLogic: AnyObject { func displayMeetupEvents(viewModel: MeetupEventList.FetchEvents.ViewModel) func displayUpdateHistoryEvent(viewModel: MeetupEventList.UpdateHistoryEvent.ViewModel)
} final class MeetupEventListViewController: UIViewController, MeetupEventListDisplayLogic { } protocol MeetupEventListBusinessLogic { func fetchMeetupEvents(request: MeetupEventList.FetchEvents.Request) func tapFavorite(request: MeetupEventList.TapFavorite.Request) func subscribeFavoriteUpdate(request: MeetupEventList.SubscribeFavoriteUpdate.Request) func unsubscribeFavoriteUpdate(request: MeetupEventList.UnsubscribeFavoriteUpdate.Request) } final class MeetupEventListInteractor: MeetupEventListBusinessLogic { } protocol MeetupEventListPresentationLogic { func presentMeetupEvents(response: MeetupEventList.FetchEvents.Response) func presentUpdateHistoryEvent(response: MeetupEventList.UpdateHistoryEvent.Response) } final class MeetupEventListPresenter: MeetupEventListPresentationLogic { }
BusinessLogic in out Boundary private func private func private func
private func Test
What’s more?
ViewController Interactor DataStore Router Data Passing Routing
Workshop Practice
None
基礎版 進階版
None
None
Interactor Presenter ViewController Request Response ViewModel struct Request { }
struct ViewModel { let historyEvents: [] let recentlyEvents: [] } struct Response { let recentlyEvents: [EventResponseItem] let historyEvents: [EventResponseItem] }
enum MeetupEventList { enum FetchEvents { struct Request { }
struct Response { let recentlyEvents: [EventResponseItem] let historyEvents: [EventResponseItem] } struct ViewModel { let historyEvents: [DisplayHistoryEvent] let recentlyEvents: [DisplayRecentlyEvent] } } }
Presentation Model
struct DisplayRecentlyEvent { let id: String let title: String let
dateText: String let hostName: String let coverImageURL: URL? }
struct DisplayHistoryEvent { let id: String let title: String let
dateText: String let hostName: String let coverImageURL: URL? let favoriteButtonColor: UIColor }
How?
class MeetupEventListViewController: UIViewController { } var recentlyEvents: [MeetupEvent] = []
var historyEvents: [MeetupEvent] = [] ViewController (MVC)
var recentlyEvents: [MeetupEventList.DisplayRecentlyEvent] = [] var historyEvents: [MeetupEventList.DisplayHistoryEvent] = []
protocol MeetupEventListDisplayLogic: AnyObject { func displayMeetupEvents( viewModel: MeetupEventList.FetchEvents.ViewModel ) } class MeetupEventListViewController: UIViewController, MeetupEventListDisplayLogic { } ViewController (Clean Swift)
meetupEventListAPI.fetchMeetupEvents { [weak self] result in guard let self =
self else { return } switch result { case let .success((recentlyEvents, historyEvents)): self.recentlyEvents = self.recentlyEvents self.historyEvents = self.historyEvents self.tableView.reloadData() case let .failure(error): print("#### error -> \(error)") } } loadData( ) (MVC)
let request: MeetupEventList.FetchEvents.Request = .init() interactor?.fetchMeetupEvents(request: request) loadData( ) (Clean
Swift)
func configureCell(with meetupEvent: MeetupEvent) { titleLabel.text = meetupEvent.title hostNameLabel.text =
meetupEvent.hostName if let eventDate = meetupEvent.date { dateLabel.text = getDateText(with: eventDate) } else { dateLabel.text = "" } coverImageView.image = nil if let coverImageUrl = meetupEvent.coverImageLink, let url = URL(string: coverImageUrl) { coverImageView.isHidden = false coverImageView.kf.setImage(with: url) } else { coverImageView.isHidden = true } } Configure Cell (MVC)
func configureCell( with meetupEvent: MeetupEventList.DisplayRecentlyEvent ) { titleLabel.text = meetupEvent.title
hostNameLabel.text = meetupEvent.hostName dateLabel.text = meetupEvent.dateText coverImageView.image = nil if let url = meetupEvent.coverImageURL { coverImageView.isHidden = false coverImageView.kf.setImage(with: url) } else { coverImageView.isHidden = true } } Configure Cell (Clean Swift)
protocol MeetupEventListBusinessLogic { func fetchMeetupEvents( request: MeetupEventList.FetchEvents.Request ) } class
MeetupEventListInteractor: MeetupEventListBusinessLogic{ var fetchMeetupEventWorker: MeetupEventListAPIWorker func fetchMeetupEvents( request:MeetupEventList.FetchEvents.Request ) { } } Interactor (Clean Swift)
protocol MeetupEventListPresentationLogic { func presentMeetupEvents( response: MeetupEventList.FetchEvents.Response ) } class
MeetupEventListPresenter:MeetupEventListPresentationLogic { func presentMeetupEvents( response: MeetupEventList.FetchEvents.Response ){ } } Presenter (Clean Swift)
活動時間: 每週⼆ pm: 8:30 ~ 10:00 (每⽉第⼀週休) 活動地點:線上聚會 || Meet.jobs
辦公室 (感謝Meet.jobs 提供場地)
聯絡資訊(email) 聯絡資訊(LinkedIn) 我們在招⼈~ beanfun!的iOS團隊需要你 ⽬前我們正在以Clean Swift為主架構 重構整個beanfun! App ⽬前預計明年1⽉會上線
如果你對這個機會有興趣,想了解更多資訊 歡迎email給我,或加我LinkedIn聊聊唷
練習專案 完成版 Clean Swift 討論群
Thanks for your attention.