Slide 1

Slide 1 text

Clean Swift A better architecture to make project testable iOS@Taipei 艾倫 Ni & William Kuo

Slide 2

Slide 2 text

What is Clean Swift?

Slide 3

Slide 3 text

ViewController

Slide 4

Slide 4 text

Scene

Slide 5

Slide 5 text

Interactor Presenter ViewController

Slide 6

Slide 6 text

ViewController Interactor Presenter Display
 Logic Business
 Logic Presentation
 Logic ViewController Interactor Presenter Display
 Logic Business
 Logic Presenta tion
 Logic

Slide 7

Slide 7 text

ViewControll Interact Presenter Display
 Logic Business
 Logic Presentation
 Logic Worker Worker Worker

Slide 8

Slide 8 text

Worker ORM / DB Local API Network / API Network API ViewControll Interact Presenter Display
 Logic Business
 Logic Presentation
 Logic

Slide 9

Slide 9 text

Worker ViewControll Interact Presenter Display
 Logic Business
 Logic Presentation
 Logic I13N Calculate Thumbnail resize Parse video’s metadata

Slide 10

Slide 10 text

Interactor Presenter ViewController Request Response ViewModel

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Boundary

Slide 13

Slide 13 text

viewContorller interactor presentor in out in out DisplayLogic in out Boundary Boundary Boundary BusinessLogic Presentation Logic

Slide 14

Slide 14 text

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 { }

Slide 15

Slide 15 text

BusinessLogic in out Boundary private func private func private func private func Test

Slide 16

Slide 16 text

What’s more?

Slide 17

Slide 17 text

ViewController Interactor DataStore Router Data Passing Routing

Slide 18

Slide 18 text

Workshop Practice

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

基礎版 進階版

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Interactor Presenter ViewController Request Response ViewModel struct Request { } struct ViewModel { let historyEvents: [] let recentlyEvents: [] } struct Response { let recentlyEvents: [EventResponseItem] let historyEvents: [EventResponseItem] }

Slide 24

Slide 24 text

enum MeetupEventList { enum FetchEvents { struct Request { } struct Response { let recentlyEvents: [EventResponseItem] let historyEvents: [EventResponseItem] } struct ViewModel { let historyEvents: [DisplayHistoryEvent] let recentlyEvents: [DisplayRecentlyEvent] } } }

Slide 25

Slide 25 text

Presentation Model

Slide 26

Slide 26 text

struct DisplayRecentlyEvent { let id: String let title: String let dateText: String let hostName: String let coverImageURL: URL? }

Slide 27

Slide 27 text

struct DisplayHistoryEvent { let id: String let title: String let dateText: String let hostName: String let coverImageURL: URL? let favoriteButtonColor: UIColor }

Slide 28

Slide 28 text

How?

Slide 29

Slide 29 text

class MeetupEventListViewController: UIViewController { } var recentlyEvents: [MeetupEvent] = [] var historyEvents: [MeetupEvent] = [] ViewController (MVC)

Slide 30

Slide 30 text

var recentlyEvents: [MeetupEventList.DisplayRecentlyEvent] = [] var historyEvents: [MeetupEventList.DisplayHistoryEvent] = [] protocol MeetupEventListDisplayLogic: AnyObject { func displayMeetupEvents( viewModel: MeetupEventList.FetchEvents.ViewModel ) } class MeetupEventListViewController: UIViewController, MeetupEventListDisplayLogic { } ViewController (Clean Swift)

Slide 31

Slide 31 text

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)

Slide 32

Slide 32 text

let request: MeetupEventList.FetchEvents.Request = .init() interactor?.fetchMeetupEvents(request: request) loadData( ) (Clean Swift)

Slide 33

Slide 33 text

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)

Slide 34

Slide 34 text

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)

Slide 35

Slide 35 text

protocol MeetupEventListBusinessLogic { func fetchMeetupEvents( request: MeetupEventList.FetchEvents.Request ) } class MeetupEventListInteractor: MeetupEventListBusinessLogic{ var fetchMeetupEventWorker: MeetupEventListAPIWorker func fetchMeetupEvents( request:MeetupEventList.FetchEvents.Request ) { } } Interactor (Clean Swift)

Slide 36

Slide 36 text

protocol MeetupEventListPresentationLogic { func presentMeetupEvents( response: MeetupEventList.FetchEvents.Response ) } class MeetupEventListPresenter:MeetupEventListPresentationLogic { func presentMeetupEvents( response: MeetupEventList.FetchEvents.Response ){ } } Presenter (Clean Swift)

Slide 37

Slide 37 text

活動時間: 每週⼆ pm: 8:30 ~ 10:00 (每⽉第⼀週休) 活動地點:線上聚會 || Meet.jobs 辦公室 (感謝Meet.jobs 提供場地)

Slide 38

Slide 38 text

聯絡資訊(email) 聯絡資訊(LinkedIn) 我們在招⼈~
 beanfun!的iOS團隊需要你
 
 ⽬前我們正在以Clean Swift為主架構
 重構整個beanfun! App ⽬前預計明年1⽉會上線 如果你對這個機會有興趣,想了解更多資訊 歡迎email給我,或加我LinkedIn聊聊唷

Slide 39

Slide 39 text

練習專案 完成版 Clean Swift 討論群

Slide 40

Slide 40 text

Thanks for your attention.