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
Clean Swift Workshop
Search
Chiaote Ni
November 08, 2020
Programming
820
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
130
Swift Testing - iPlayground
chiaoteni
0
300
Swift Package Manager
chiaoteni
0
160
Swift Smart KeyPath
chiaoteni
0
1.4k
Other Decks in Programming
See All in Programming
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
1.6k
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
360
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
300
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.7k
act1-costs.pdf
sumedhbala
0
170
20260623_Loop Engineeringで自分の分身の問い合わせBotを作る
ryugen04
0
170
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
390
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
830
フィードバックで育てるAI開発
kotaminato
1
110
SLOをサービス品質の共通言語にするために 取り組んできたこと
wakana0222
0
380
dRuby over BLE
makicamel
2
410
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
Featured
See All Featured
Google's AI Overviews - The New Search
badams
0
1.1k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
560
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
180
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
RailsConf 2023
tenderlove
30
1.5k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.2k
The Language of Interfaces
destraynor
162
27k
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
260
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.