Giter Site home page Giter Site logo

plan's Introduction

Plan

Build Carthage compatible codecov Version Platform License

The Plan.framework helps to keep your iOS application design clean. Think of it as a clean architecture. Read about clean architecture here.

overview

The purpose of this design is to clear the processing flow and dependencies.

The ideal processing flow is as follows.

If it is difficult to accept processing in Controller, you may prepare Adapter instead of Controller and Adapter may interact with Controller. However, the Adapter should not do more than necessary.

Details

Plan offers five main types, but in many cases a framework that allows reactive programming is helpful.

Interactor

Input from Controller is processed. Data I/O and API calls are also performed here. When the processing is completed, execute the action of Dispatcher. It is included in the Domain Layer.

enum LoginUseCaseAction {
    case loading
    case login(Result<User, Error>)
}

protocol LoginUseCase {
    func login(userName: String, password: String)
}

class LoginInteractor: Interactor<LoginUseCaseAction>, LoginUseCase {
    let disposeBag = DisposeBag()

    func login(userName: String, password: String) {
        dispatcher.dispatch(.loading)
        userRepository.login(userName: userName, password: password)
            .subscribe(onNext: { [weak self] user in
                self?.dispatcher.dispatch(.login(.success(user)))
            }, onError: { [weak self] error in
                self?.dispatcher.dispatch(.login(.failure(error)))
            })
            .disposed(by: disposeBag)
    }
}

Dispatcher

Pass the Output by Interactor to Translator.

Store

Store the state of View. The status is changed by the Translator. It is included in the Presentation Layer.

class LoginStore: Store {
    let viewModel = BehaviorRelay(value: LoginViewModel())
}

Translator

The data received from the Interactor is converted into the data for configuring the View and the state of the Store is updated. It is included in the Presentation Layer.

struct LoginTranslator: Translator {
    func translate(action: LoginUseCaseAction, store: LoginStore) {
        switch action {
        case .loading:
            store.viewModel.modefy { viewModel in
                viewModel.loginProgress = .loading
            }

        case .login(.success(let user)):
            store.viewModel.modefy { viewModel in
                viewModel.user = user
                viewModel.loginProgress = .loadSucceeded
            }

        case .login(.failure(let error)):
            print("login failed \(error)")
            store.viewModel.modefy { viewModel in
                viewModel.loginProgress = .loadFailed
            }
        }
    }
}

Presenter

Convert the stored state to the optimal form for View to use. It is included in the Presentation Layer.

class LoginPresenter: Presenter<LoginTranslator>, LoginPresenterProtocol {
    var viewModel: Observable<LoginViewModel> {
        store.viewModel.asObservable()
    }
}

When initializing the Interactor, pass the Presenter instance as the Dispatcher.

let presenter = LoginPresenter(store: LoginStore(), translator: LoginTranslator())
let interactor = LoginInteractor(dispatcher: presenter.asDispatcher())

Normally, the Action that can be dispatched to the Presenter is limited to the one defined in the Translator, but if there are multiple UseCase, by overloading the asDispatcher() method, It is possible to dispatch to multiple Interactor.

class LoginPresenter: Presenter<LoginTranslator>, LoginPresenterProtocol {
    var viewModel: Observable<LoginViewModel> {
        store.viewModel.asObservable()
    }

    func asDispatcher() -> AnyDispatcher<UserInfoUseCaseAction> {
        AnyDispatcher(self)
            .map { (action: UserInfoUseCaseAction) in
                // Convert UserInfoUseCaseAction to LoginTranslator.Action
        }
    }
}

let presenter = LoginPresenter(store: LoginStore(), translator: LoginTranslator())

// Can dispatch to one Presenter from multiple Interactors.
let loginInteractor = LoginInteractor(dispatcher: presenter.asDispatcher())
let userInfoInteractor = UserInfoInteractor(dispatcher: presenter.asDispatcher())

More details

See Examples.

Requirements

  • Swift 5.0
  • iOS 10.0 or later
  • macOS 10.12 or later
  • tvOS 10.0 or later
  • watchOS 3.0 or later

Installation

CocoaPods

Add the following to your Podfile:

pod "Plan"

Carthage

Add the following to your Cartfile:

github "KyoheiG3/Plan"

Acknowledgements

I've always used VueFlux inside the architecture, but I've created a Plan in an attempt to make it simpler and easier for module testing.

LICENSE

Under the MIT license. See LICENSE file for details.

plan's People

Contributors

kyoheig3 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.