All Projects → sergdort → Cleanarchitecturerxswift

sergdort / Cleanarchitecturerxswift

Licence: mit
Example of Clean Architecture of iOS app using RxSwift

Programming Languages

swift
15916 projects
objective c
16641 projects - #2 most used programming language
ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Cleanarchitecturerxswift

Viabus Architecture
让 Android 开发可以像流水线一样高效的,职责分离架构 ⚡ 不同于 MVP 的配置解耦,也不能和 似是而非 的 MVVM - Clean 同日而语。VIABUS 是世界范围内首个明确提出,通过职责分离,来真正实现 UI 和 业务并行开发的 Android 项目级开发架构和设计模式理念。
Stars: ✭ 485 (-85.1%)
Mutual labels:  reactive-programming, architecture, mvvm, clean-architecture
MGCleanArchitecture
Clean Architecture with RxSwift & MVVM - Templates and Solutions
Stars: ✭ 156 (-95.21%)
Mutual labels:  rxswift, mvvm, coredata, clean-architecture
Clean Architecture Swiftui
SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.
Stars: ✭ 2,925 (-10.17%)
Mutual labels:  coredata, architecture, mvvm, clean-architecture
Exchange Rates Mvvm
Sample Android project which incorporates MVVM, databinding, RxJava2, Dagger2 and Clean Architecture approach.
Stars: ✭ 43 (-98.68%)
Mutual labels:  realm, mvvm, clean-architecture
Ios Architectures
Sample app for iOS architectures
Stars: ✭ 90 (-97.24%)
Mutual labels:  architecture, mvvm, clean-architecture
Android Showcase
💎 Android application following best practices: Kotlin, Coroutines, JetPack, Clean Architecture, Feature Modules, Tests, MVVM, DI, Static Analysis...
Stars: ✭ 5,214 (+60.14%)
Mutual labels:  architecture, mvvm, clean-architecture
Ios Architecture
A collection of iOS architectures - MVC, MVVM, MVVM+RxSwift, VIPER, RIBs and many others
Stars: ✭ 901 (-72.33%)
Mutual labels:  rxswift, architecture, mvvm
TVToday
iOS TV Shows app with TMDb Api. RxSwift, MVVM, Clean Architecture. Tuist + Swift Package Manager
Stars: ✭ 27 (-99.17%)
Mutual labels:  rxswift, mvvm, clean-architecture
Coordinator Mvvm Rx Example
Example of MVVM-C architecture implemented with RxSwift
Stars: ✭ 469 (-85.6%)
Mutual labels:  rxswift, architecture, mvvm
Mvvmc Splitviewcontroller
Example project with UITabBarController inside UISplitViewController using RxSwift and MVVM-C architecture.
Stars: ✭ 45 (-98.62%)
Mutual labels:  rxswift, architecture, mvvm
Offlinesampleapp
Sample Offline-First MVVM app that uses Android Priority Job Queue, Room, Retrofit2, LiveData, LifecycleObserver, RxJava2, Dagger Android
Stars: ✭ 653 (-79.94%)
Mutual labels:  reactive-programming, mvvm, clean-architecture
Sesame
Android architecture components made right
Stars: ✭ 48 (-98.53%)
Mutual labels:  reactive-programming, architecture, mvvm
Swift Design Patterns
🚀 The ultimate collection of various Software Design Patterns implemented in Swift [Swift 5.0, 28 Patterns].
Stars: ✭ 85 (-97.39%)
Mutual labels:  architecture, mvvm, clean-architecture
Ios Clean Architecture Mvvm
Template iOS app using Clean Architecture and MVVM. Includes DIContainer, FlowCoordinator, DTO, Response Caching and one of the views in SwiftUI
Stars: ✭ 753 (-76.87%)
Mutual labels:  architecture, mvvm, clean-architecture
iOS-Clean-Architecture-Example
An iOS app designed using clean architecture and MVVM.
Stars: ✭ 50 (-98.46%)
Mutual labels:  architecture, mvvm, clean-architecture
Gitiny
An iOS app for GitHub with exploring trending
Stars: ✭ 247 (-92.41%)
Mutual labels:  rxswift, realm, clean-architecture
SwiftObserver
Elegant Reactive Primitives for Clean Swift Architecture #NoRx
Stars: ✭ 14 (-99.57%)
Mutual labels:  rxswift, reactive-programming, clean-architecture
Mp3ID3Tagger
🎶🎵A macOS application to edit the ID3 tag of your mp3 files. Developed with RxSwift and RxCocoa. 🎸🎼
Stars: ✭ 17 (-99.48%)
Mutual labels:  rxswift, mvvm, reactive-programming
ApolloRickAndMorty
just a side project to try out GraphQL and Dagger Hilt with Clean architecture and MVVM
Stars: ✭ 28 (-99.14%)
Mutual labels:  mvvm, clean-architecture
paybill-manager
Your personal finance manager
Stars: ✭ 46 (-98.59%)
Mutual labels:  mvvm, clean-architecture

Clean architecture with RxSwift

Contributions are welcome and highly appreciated!!

You can do this by:

  • opening an issue to discuss the current solution, ask a question, propose your solution etc. (also English is not my native language so if you think that something can be corrected please open a PR 😊)
  • opening a PR if you want to fix bugs or improve something

Installation

Dependencies in this project are provided via Cocoapods. Please install all dependecies with

pod install

High level overview

Domain

The Domain is basically what is your App about and what it can do (Entities, UseCase etc.) It does not depend on UIKit or any persistence framework, and it doesn't have implementations apart from entities

Platform

The Platform is a concrete implementation of the Domain in a specific platform like iOS. It does hide all implementation details. For example Database implementation whether it is CoreData, Realm, SQLite etc.

Application

Application is responsible for delivering information to the user and handling user input. It can be implemented with any delivery pattern e.g (MVVM, MVC, MVP). This is the place for your UIViews and UIViewControllers. As you will see from the example app, ViewControllers are completely independent of the Platform. The only responsibility of a view controller is to "bind" the UI to the Domain to make things happen. In fact, in the current example we are using the same view controller for Realm and CoreData.

Detail overview

To enforce modularity, Domain, Platform and Application are separate targets in the App, which allows us to take advantage of the internal access layer in Swift to prevent exposing of types that we don't want to expose.

Domain

Entities are implemented as Swift value types

public struct Post {
    public let uid: String
    public let createDate: Date
    public let updateDate: Date
    public let title: String
    public let content: String
}

UseCases are protocols which do one specific thing:

public protocol PostsUseCase {
    func posts() -> Observable<[Post]>
    func save(post: Post) -> Observable<Void>
}

UseCaseProvider is a service locator. In the current example, it helps to hide the concrete implementation of use cases.

Platform

In some cases, we can't use Swift structs for our domain objects because of DB framework requirements (e.g. CoreData, Realm).

final class CDPost: NSManagedObject {
    @NSManaged public var uid: String?
    @NSManaged public var title: String?
    @NSManaged public var content: String?
    @NSManaged public var createDate: NSDate?
    @NSManaged public var updateDate: NSDate?
}

final class RMPost: Object {
    dynamic var uid: String = ""
    dynamic var createDate: NSDate = NSDate()
    dynamic var updateDate: NSDate = NSDate()
    dynamic var title: String = ""
    dynamic var content: String = ""
}

The Platform also contains concrete implementations of your use cases, repositories or any services that are defined in the Domain.

final class PostsUseCase: Domain.PostsUseCase {
    
    private let repository: AbstractRepository<Post>

    init(repository: AbstractRepository<Post>) {
        self.repository = repository
    }

    func posts() -> Observable<[Post]> {
        return repository.query(sortDescriptors: [Post.CoreDataType.uid.descending()])
    }
    
    func save(post: Post) -> Observable<Void> {
        return repository.save(entity: post)
    }
}

final class Repository<T: CoreDataRepresentable>: AbstractRepository<T> where T == T.CoreDataType.DomainType {
    private let context: NSManagedObjectContext
    private let scheduler: ContextScheduler

    init(context: NSManagedObjectContext) {
        self.context = context
        self.scheduler = ContextScheduler(context: context)
    }

    override func query(with predicate: NSPredicate? = nil,
                        sortDescriptors: [NSSortDescriptor]? = nil) -> Observable<[T]> {
        let request = T.CoreDataType.fetchRequest()
        request.predicate = predicate
        request.sortDescriptors = sortDescriptors
        return context.rx.entities(fetchRequest: request)
            .mapToDomain()
            .subscribeOn(scheduler)
    }

    override func save(entity: T) -> Observable<Void> {
        return entity.sync(in: context)
            .mapToVoid()
            .flatMapLatest(context.rx.save)
            .subscribeOn(scheduler)
    }
}

As you can see, concrete implementations are internal, because we don't want to expose our dependecies. The only thing that is exposed in the current example from the Platform is a concrete implementation of the UseCaseProvider.

public final class UseCaseProvider: Domain.UseCaseProvider {
    private let coreDataStack = CoreDataStack()
    private let postRepository: Repository<Post>

    public init() {
        postRepository = Repository<Post>(context: coreDataStack.context)
    }

    public func makePostsUseCase() -> Domain.PostsUseCase {
        return PostsUseCase(repository: postRepository)
    }
}

Application

In the current example, Application is implemented with the MVVM pattern and heavy use of RxSwift, which makes binding very easy.

Where the ViewModel performs pure transformation of a user Input to the Output

protocol ViewModelType {
    associatedtype Input
    associatedtype Output
    
    func transform(input: Input) -> Output
}
final class PostsViewModel: ViewModelType {
    struct Input {
        let trigger: Driver<Void>
        let createPostTrigger: Driver<Void>
        let selection: Driver<IndexPath>
    }
    struct Output {
        let fetching: Driver<Bool>
        let posts: Driver<[Post]>
        let createPost: Driver<Void>
        let selectedPost: Driver<Post>
        let error: Driver<Error>
    }
    
    private let useCase: AllPostsUseCase
    private let navigator: PostsNavigator
    
    init(useCase: AllPostsUseCase, navigator: PostsNavigator) {
        self.useCase = useCase
        self.navigator = navigator
    }
    
    func transform(input: Input) -> Output {
       ......
    }

A ViewModel can be injected into a ViewController via property injection or initializer. In the current example, this is done by Navigator.

protocol PostsNavigator {
    func toCreatePost()
    func toPost(_ post: Post)
    func toPosts()
}

class DefaultPostsNavigator: PostsNavigator {
    private let storyBoard: UIStoryboard
    private let navigationController: UINavigationController
    private let services: ServiceLocator
    
    init(services: ServiceLocator,
         navigationController: UINavigationController,
         storyBoard: UIStoryboard) {
        self.services = services
        self.navigationController = navigationController
        self.storyBoard = storyBoard
    }
    
    func toPosts() {
        let vc = storyBoard.instantiateViewController(ofType: PostsViewController.self)
        vc.viewModel = PostsViewModel(useCase: services.getAllPostsUseCase(),
                                      navigator: self)
        navigationController.pushViewController(vc, animated: true)
    }
    ....
}

class PostsViewController: UIViewController {
    private let disposeBag = DisposeBag()
    
    var viewModel: PostsViewModel!
    
    ...
}

Example

The example app is Post/TODOs app which uses Realm, CoreData and Network at the same time as a proof of concept that the Application level is not dependant on the Platform level implementation details.

CoreData Realm Network

Modularization

The corner stone of Clean Architecture is modularization, as you can hide implementation detail under internal access layer. Further read of this topic here

TODO:

  • add tests
  • add MVP example
  • Redux example??

Links

Any questions?

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].