Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Taste of MVVM + RxSwift

Khoa Pham
November 25, 2017

A Taste of MVVM + RxSwift

My talk at Mobile Era 2016

Khoa Pham

November 25, 2017
Tweet

More Decks by Khoa Pham

Other Decks in Programming

Transcript

  1. aka THE 100TH TALK ABOUT MVVM, RXSWIFT ! WHY DO

    PEOPLE KEEP TALKING ABOUT THIS ?
  2. 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 ...
  3. let buzzWords = [ "Model", "View", "Controller", "Entity", "Router", "Clean",

    "Reactive", "Presenter", "Interactor", "Megatron", "Coordinator", "Flow", "Manager" ] let architecture = buzzWords.shuffled().takeRandom() let acronym = architecture.makeAcronym()
  4. 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 } }
  5. class ViewModel { func getFacebookFriends(completion: [User] -> Void) { let

    client = APIClient() client.getFacebookFriends(for: user) { friends in DispatchQueue.main.async { completion(friends) } } } }
  6. BINDING class Binding<T> { 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 } }
  7. class ViewModel { let friends = Binding<[User]>(value: []) init() {

    getFacebookFriends { friends.value = $0 } } func getFacebookFriends(completion: ([User]) -> Void) { // Do the work } }
  8. 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() }) } }
  9. 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()) }
  10. VIEWCONTROLLER AND VIEW class BaseViewController<V: UIView>: UIViewController { lazy var

    root: V = V() override func viewDidLoad() { super.viewDidLoad() view.addSubview(root) } }
  11. class ProfileView: UIView { // Construct subviews and do Auto

    Layout here } class ProfileViewController: BaseViewController<ProfileView> { // Handle actions from view } let profileVC = ProfileViewController() navigationController.pushViewController(profileVC, animated: true)
  12. 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 } }
  13. class ProfileViewController: BaseViewController<ProfileView> { 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)" }) } }