RxCleanSwift icon indicating copy to clipboard operation
RxCleanSwift copied to clipboard

Clean Swift 연구일지 #1

Open GeekTree0101 opened this issue 5 years ago • 0 comments

문제점

  1. 콜백구조 맘에 안듦
  2. List에 있는 Item에 대해서 (특정 IndexPath) DataStore를 통해 item을 가져와서 Show 로 보내고 다시 리스트로 되돌아갔을 때 DataPassing해줌과 동시에 interactor를 통해서 다시 present -> controller 과정을 거치는게 비효율적이라고 생각함

해결방안

1. RxSwift를 활용하여 VIP Cycle binding 및 reactive property로 설계

했을 때 장점이라면 콜백 지옥으로 부터 해방, 단점은 RxTest 잘써야되고 아직 관련 VIP템플릿이 없어서 새로만들어야함 그리고 I -> P, P -> C VIP Cycle binding처리할 때 disposable 를 반환시키는데 이에 대한 disposeBag은 Controller에서 가지고 있는게 맞다고 생각함

    func configureVIPCycle() {
        // configure VIP Cycle
        let viewController = self
        let interactor = RepositoryShowInteractor.init()
        let presenter = RepositoryShowPresenter.init()
        let router = RepositoryShowRouter()
        
        // HERE!
        interactor.bind(to: presenter).disposed(by: disposeBag)
        presenter.bind(to: viewController).disposed(by: disposeBag)
        router.bind(to: viewController).disposed(by: disposeBag)

    // ....
   }

2. ReactiveDataStore를 양방향으로 DataPassing해서 사용

public class ReactiveDataStore<T> {
    
    public let store: BehaviorRelay<T>
    
    public var value: T {
        return store.value
    }
    
    init(_ data: T) {
        store = .init(value: data)
    }
    
    public func update(_ data: T) {
        store.accept(data)
    }
    
    public func asObservable() -> Observable<T> {
        return store.asObservable()
    }
}

위와 같이 어떤 Model에 대해서 Reactive하게 쓸 수 있게 Wrapping해서 만든 Class ViewModel을 다음과 같이 Store를 받아서 만들면 해당 Store가 다른 Controller에 전달되서 변경에 따라 자동으로 ViewModel의 State값도 변경됌

            struct CellViewModel {
                
                struct State {
                    var profileURL: URL?
                    var title: String?
                    var desc: String?
                    var isPinned: Bool
                    
                    init(_ repo: Repository) {
                        self.profileURL =  repo.user?.profileURL
                        self.title = repo.user?.username
                        self.desc = repo.desc
                        self.isPinned = repo.isPinned
                    }
                }
                
                let state = BehaviorRelay<State?>(value: nil)
                let identifier: Int
                
                private let disposeBag = DisposeBag()
                
                init(_ repositoryStore: ReactiveDataStore<Repository>) {
                    
                    repositoryStore
                        .asObservable()
                        .map({ State($0) })
                        .bind(to: state)
                        .disposed(by: disposeBag)
                    
                    self.identifier = repositoryStore.value.id
                }
            }

GeekTree0101 avatar Apr 17 '19 01:04 GeekTree0101