Slide 1

Slide 1 text

A TASTE OF MVVM + RXSWIFT

Slide 2

Slide 2 text

aka THE 100TH TALK ABOUT MVVM, RXSWIFT ! WHY DO PEOPLE KEEP TALKING ABOUT THIS ?

Slide 3

Slide 3 text

ABOUT > [email protected] > https://github.com/onmyway133 > https://github.com/hyperoslo

Slide 4

Slide 4 text

OBJECT ORIENTED PROGRAMMING > characteristics > action

Slide 5

Slide 5 text

PROJECT MANAGER > Designer > Tester > Scrum Master > Developer -> Freelancer

Slide 6

Slide 6 text

MVC Source https://www.raywenderlich.com

Slide 7

Slide 7 text

UIVIEWCONTROLLER func viewDidLoad() var preferredStatusBarStyle: UIStatusBarStyle { get } UITableViewDataSource var presentationController: UIPresentationController? { get } func childViewControllerForScreenEdgesDeferringSystemGestures() -> UIViewController? func didMove(toParentViewController parent: UIViewController?) var systemMinimumLayoutMargins: NSDirectionalEdgeInsets var edgesForExtendedLayout: UIRectEdge var previewActionItems: [UIPreviewActionItem] var navigationItem: UINavigationItem var shouldAutorotate: Bool ...

Slide 8

Slide 8 text

VIPER View Interactor Presenter Entity Routing

Slide 9

Slide 9 text

FCPN Functional Controller Presenter Navigator

Slide 10

Slide 10 text

CRSC Clean Reactor Store Coordinator

Slide 11

Slide 11 text

MRRI Megatron Router Reactive Interactor

Slide 12

Slide 12 text

let buzzWords = [ "Model", "View", "Controller", "Entity", "Router", "Clean", "Reactive", "Presenter", "Interactor", "Megatron", "Coordinator", "Flow", "Manager" ] let architecture = buzzWords.shuffled().takeRandom() let acronym = architecture.makeAcronym()

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

ARCHITECTURE > Separation of concerns > Communication pattern > Comfortable to use

Slide 15

Slide 15 text

SAVING PRIVATE VIEWCONTROLLER

Slide 16

Slide 16 text

MVVM source https://www.raywenderlich.com

Slide 17

Slide 17 text

MVVM > Self contained > Testable > Good enough. Comfortable. > Improve existing ViewController

Slide 18

Slide 18 text

synchronously class ProfileController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let viewModel = ViewModel(user: user) nameLabel.text = viewModel.name birthdayLabel.text = viewModel.birthdayString salaryLabel.text = viewModel.salary piLabel.text = viewModel.millionthDigitOfPi } }

Slide 19

Slide 19 text

asynchronously viewModel.getFacebookFriends { friends in self.friendCountLabel.text = "\(friends.count)" }

Slide 20

Slide 20 text

class ViewModel { func getFacebookFriends(completion: [User] -> Void) { let client = APIClient() client.getFacebookFriends(for: user) { friends in DispatchQueue.main.async { completion(friends) } } } }

Slide 21

Slide 21 text

> KVO > Delegate > Notification > Closure

Slide 22

Slide 22 text

BINDING class Binding { var value: T { didSet { listener?(value) } } private var listener: ((T) -> Void)? init(value: T) { self.value = value } func bind(_ closure: @escaping (T) -> Void) { closure(value) listener = closure } }

Slide 23

Slide 23 text

class ViewModel { let friends = Binding<[User]>(value: []) init() { getFacebookFriends { friends.value = $0 } } func getFacebookFriends(completion: ([User]) -> Void) { // Do the work } }

Slide 24

Slide 24 text

override func viewDidLoad() { super.viewDidLoad() viewModel.friends.bind { friends in self.friendsCountLabel.text = "\(friends.count)" } }

Slide 25

Slide 25 text

RXSWIFT https://github.com/ReactiveX/RxSwift

Slide 26

Slide 26 text

OBSERVABLE Source http://rxmarbles.com/#filter

Slide 27

Slide 27 text

class ViewModel { let friends: Observable<[User]> init() { let client = APIClient() friends = Observable<[User]>.create({ subscriber in client.getFacebookFriends(completion: { friends in subscriber.onNext(friends) subscriber.onCompleted() }) return Disposables.create() }) } }

Slide 28

Slide 28 text

override func viewDidLoad() { super.viewDidLoad() viewModel.friends.subscribe(onNext: { friends in self.friendsCountLabel.text = "\(friends.count)" }) }

Slide 29

Slide 29 text

let facebookFriends: Observable<[User]> // network request let twitterFriends: Observable<[User]> // network request let totalFriends: Observable<[User]> = Observable.combineLatest([facebookFriends, twitterFriends]) { friends in return Array(friends.joined()) }

Slide 30

Slide 30 text

VIEWCONTROLLER AND VIEW class BaseViewController: UIViewController { lazy var root: V = V() override func viewDidLoad() { super.viewDidLoad() view.addSubview(root) } }

Slide 31

Slide 31 text

class ProfileView: UIView { // Construct subviews and do Auto Layout here } class ProfileViewController: BaseViewController { // Handle actions from view } let profileVC = ProfileViewController() navigationController.pushViewController(profileVC, animated: true)

Slide 32

Slide 32 text

INPUT OUTPUT class ViewModel { class Input { let fetch = PublishSubject<()>() } class Output { let friends: Driver<[User]> } let apiClient: APIClient let input: Input let output: Output init(apiClient: APIClient) { self.apiClient = apiClient // Connect input and output } }

Slide 33

Slide 33 text

class ProfileViewController: BaseViewController { let viewModel: ProfileViewModelType init(viewModel: ProfileViewModelType) { self.viewModel = viewModel } override func viewDidLoad() { super.viewDidLoad() // Input viewModel.input.fetch.onNext(()) // Output viewModel.output.friends.subscribe(onNext: { friends in self.friendsCountLabel.text = "\(friends.count)" }) } }

Slide 34

Slide 34 text

Q & A