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)
  ...