This application was written in order to use Realm, RxSwift frameworks in real example

Realm_RxSwift

This simple app was written to introduce basic operations of some frameworks. Such as “Realm” and “RxSwift”. Also this app was written with MVVM pattern with Coordinators.

Coordinator

Here we are declaring our functions with protocol.

  protocol AppCoordinatorProtocol {
      var window: UIWindow { get }
      var navigationController: UINavigationController { get }

      func start()
      func startDatasVC(userModel: UserModel, editRelay: PublishRelay<UserModel?>?)
      func showAddUserAlert(_ relay: PublishRelay<String?>)
      func showError(with msg: String)
  }

Here we are initialising our protocol.

  class AppCoordinator: AppCoordinatorProtocol {

      var window: UIWindow
      var navigationController: UINavigationController

      init(window: UIWindow) {
          self.window = window
          self.navigationController = UINavigationController()
          self.window.rootViewController = navigationController
      }

      func start() {
          self.window.makeKeyAndVisible()
          let mainVC = MainVC.instantiate()
          mainVC.appCoordinator = self
          mainVC.mainViewModel = MainViewModel()
          self.navigationController.setViewControllers([mainVC], animated: true)
      }
  ...
  }

Realm(Create-Read-Update)

Create

        let newUser = UserModel()
        newUser.id = UUID().uuidString
        newUser.username = username
        newUser.selected = false

        
        do {
            try db.write {
                self.db.add(newUser)
            }
        } catch {
            //error
        }

Read(Fetching objects)

        if let usersResult = db.objects(UserModel.self) {
            let usersArray: [UserModel] = Array(usersResult)
            print(usersArray)
        } else {
            //error
        }

Update

        do {
            try db.write {
                user.selected = !user.selected
            }
        } catch {
                //error    
        }

RxSwift Traits

Completable

“Completable” is a type of RxSwift traits. “Completable” finishes with 2 functions. First is “.completed”, second is “.error(SomeError)”. In real use-case, we can use this trait when we need only information about completion or error result. For example when uploading or inserting datas. In this app I also used “Completable” trait in order to creating new UserModel:

  func addUser(username: String) -> Completable {
    return Completable.create { [weak self] observer in
        let maybeError = RealmError(msg: "Realm add user error")
        
        guard let self = self else {
            observer(.error(maybeError))
            return Disposables.create()
        }
        
        let newUser = UserModel()
        newUser.id = UUID().uuidString
        newUser.username = username
        newUser.selected = false
        
        do {
            try self.db?.write {
                self.db?.add(newUser)
                observer(.completed)
            }
        } catch {
            observer(.error(maybeError))
        }

        return Disposables.create {}
    }
}

Single

Second trait type which I used in this application is “Single”. In this trait you have 2 chances to finish. First is “.success(SomeData)”, second is “.failure(SomeError)”. In this app I used this trait in order to fetch users:

  func fetchUsers() -> Single<[UserModel]> {
    return Single<[UserModel]>.create { [weak self] observer in
        let maybeError = RealmError(msg: "Realm fetch error")
        
        guard let self = self else {
            observer(.failure(maybeError))
            return Disposables.create()
        }
        
        if let usersResult = self.db?.objects(UserModel.self) {
            let usersArray: [UserModel] = Array(usersResult)
            observer(.success(usersArray))
        } else {
            observer(.failure(maybeError))
        }
        
        return Disposables.create {}
    }
}

Driver

Third trait which I want to introduce is “Driver”. This trait is to work with UI. Because this trait works on MainThread. For instance, I used this trait when user opens alert dialog in order to add user and clicks “save” button:

  ...
  let alertRelay = PublishRelay<String?>()
  ...
  
     alertRelay
        .asDriver(onErrorJustReturn: "")
        .map { ($0 ?? "") }
        .filter { $0 != "" }
        .drive { [weak self] text in
            self?.addUser(text)
        }
        .disposed(by: bag)
  ...

GitHub

View Github