MVC & MVVM: Implementation of MVVM In RxSwift

RxSwift
Photo by Dimitri Karastelev on Unsplash
Model View Controller
Traditional MVC
  • ViewModel is not replacement for ViewController
  • Do not dump everything from ViewControllers to ViewModels
MVVM in Swift
public struct TopStoriesResponse : Codable {let results : [Results]}public struct Results : Codable {let title : Stringlet abstract : Stringlet multimedia : [Media]?}public struct Media : Codable {let url : String}
RxSwift MVVM
import Foundationimport RxSwiftimport RxCocoastruct Resource<T:Decodable>{let url : URL}extension URLRequest {static func loadRequest<T>(resource : Resource<T>) -> Observable<T>{return Observable.just(resource.url).flatMap{ url -> Observable<Data> inlet request =  URLRequest(url: url)return URLSession.shared.rx.data(request:request)}.map{ data -> T inreturn try JSONDecoder().decode(T.self, from: data)}}}
struct Resource<T:Decodable>{let url : URL}
extension URLRequest {static func loadRequest<T>(resource : Resource<T>) -> Observable<T>{
return Observable.just(resource.url).flatMap{ url -> Observable<Data> in
let request =  URLRequest(url: url)return URLSession.shared.rx.data(request:request)}
.map{ data -> T inreturn try JSONDecoder().decode(T.self, from: data)}
struct TopStoriesListViewModel {let topStoriesList = PublishSubject<[Results]>()}extension TopStoriesListViewModel {func fetchItems(disposeBag : DisposeBag) {let resource = Resource<TopStoriesResponse>.init(url: URL(string: "https://api.nytimes.com/svc/topstories/v2/home.json?api-key=wZ6nNutGYhiI7LDJQUCTva0k88twlGep")!)URLRequest.loadRequest(resource: resource).subscribe(onNext : { result inlet results = result.resultstopStoriesList.onNext(results)topStoriesList.onCompleted()}).disposed(by: disposeBag)}}
struct TopStoriesListViewModel {let topStoriesList = PublishSubject<[Results]>()}
extension TopStoriesListViewModel {func fetchItems(disposeBag : DisposeBag) {let resource = Resource<TopStoriesResponse>.init(url: URL(string: "https://api.nytimes.com/svc/topstories/v2/home.json?api-key=wZ6nNutGYhiI7LDJQUCTva0k88twlGep")!)
URLRequest.loadRequest(resource: resource).subscribe(onNext : { result in
let results = result.resultstopStoriesList.onNext(results)topStoriesList.onCompleted()}).disposed(by: disposeBag)}}
////  ViewController.swift//  RxNewYorkTimes////  Created by omair khan on 15/12/2021.//import UIKitimport SDWebImageimport RxSwiftimport RxCocoaclass ViewController: UIViewController {// TableViewprivate let tableView: UITableView = {let tableView = UITableView()tableView.register(TopNewsTableViewCell.self, forCellReuseIdentifier: "cell")tableView.translatesAutoresizingMaskIntoConstraints = falsereturn tableView}()let disposeBag = DisposeBag()private var viewModel = TopStoriesListViewModel()override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view.title = "Top Stories"setUpTableView()populateData()}// MARK: TableView setupfunc setUpTableView(){/*- Add as Subview- Add constraints- tableView Row Height*/self.view.addSubview(tableView)self.tableView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: (self.navigationController?.navigationBar.frame.height)!).isActive = trueself.tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = trueself.tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = trueself.tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = truetableView.rowHeight = 150}//MARK: Populate Datafunc populateData(){// fetch itemsself.viewModel.fetchItems(disposeBag: disposeBag)// Bind Dataself.viewModel.topStoriesList.bind(to: self.tableView.rx.items(cellIdentifier: "cell", cellType: TopNewsTableViewCell.self)){ row,item,cell incell.abbstractLabel.text = item.abstractcell.titleLabel.text = item.titlecell.myImageView.sd_setImage(with: URL(string: item.multimedia?[0].url ?? ""), placeholderImage: UIImage(named: "NY"), options: .continueInBackground, completed: nil)}}}
let disposeBag = DisposeBag()private var viewModel = TopStoriesListViewModel()
func populateData(){// fetch itemsself.viewModel.fetchItems(disposeBag: disposeBag)
self.viewModel.topStoriesList.bind(to: self.tableView.rx.items(cellIdentifier: "cell", cellType: TopNewsTableViewCell.self)){ row,item,cell in
cell.abbstractLabel.text = item.abstractcell.titleLabel.text = item.titlecell.myImageView.sd_setImage(with: URL(string: item.multimedia?[0].url ?? ""), placeholderImage: UIImage(named: "NY"), options: .continueInBackground, completed: nil)

--

--

--

An energetic and motivated individual IOS developer/ Data Science Practitioner. Apart from computer science Martial arts interests me the most.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Arrangement of TestFlight version

Cashlink Love: What Our Users Have to Say About Cashlink.

How to Draw in 3D with SwiftUI

M1 Apple Silicon and React-Native IOS Build Problems [ENG]

Build a Board Game Without the Politics (Part 1)

Embracing Algorithms in Your SwiftUI Painting App

16 Useful Extensions for SwiftUI

Recreating Hinge’s profile transition on iOS in Swift

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Umair Ishrat Khan

Umair Ishrat Khan

An energetic and motivated individual IOS developer/ Data Science Practitioner. Apart from computer science Martial arts interests me the most.

More from Medium

VIPER Design Pattern — Part 2

Combining Operators In RxSwift

Unit Tests Basics (iOS)

RxSwift usage with MVVM pattern.