Skip to content

Instantly share code, notes, and snippets.

@MartinMoizard
Created September 3, 2017 10:19
Show Gist options
  • Save MartinMoizard/4d66528a9959cbbdefa6d50394d2bfb1 to your computer and use it in GitHub Desktop.
Save MartinMoizard/4d66528a9959cbbdefa6d50394d2bfb1 to your computer and use it in GitHub Desktop.
final class SayHelloViewModel: ViewModelType {
let input: Input
let output: Output
struct Input {
let name: AnyObserver<String>
let validate: AnyObserver<Void>
}
struct Output {
let greeting: Driver<String>
}
private let nameSubject = ReplaySubject<String>.create(bufferSize: 1)
private let validateSubject = PublishSubject<Void>()
init() {
let greeting = validateSubject
.withLatestFrom(nameSubject)
.map { name in
return "Hello \(name)!"
}
.asDriver(onErrorJustReturn: ":-(")
self.output = Output(greeting: greeting)
self.input = Input(name: nameSubject.asObserver(), validate: validateSubject.asObserver())
}
}
@MartinMoizard
Copy link
Author

Can you post a code snippet? My code does not have this issue

@andriy-appuchino
Copy link

andriy-appuchino commented Jun 8, 2020

It's something like that:

class BaseViewModel {
    let disposeBag = DisposeBag()
    let activityTracker = ActivityTracker()
    let errorTracker = ErrorTracker<Errors>()
}

final class SomeViewModel: BaseViewModel {
    
    let input: Input
    let output: Output

    struct Input {
        // nothing intresting
    }

    struct Output {
        let sections: Driver<[SectionModel<CellViewModel>]>
        let activityTracker: ActivityTracker
        let errors: ErrorTracker<Errors>
    }

    override init() {
        input = Input()
        
        // prepare setCommand and selectCommand
        let sections = Observable.of(setCommand, selectCommand)
            .merge()
            .do(onNext: { [weak self] command in // <-- I get it here
                self?.sendRequest(for: command)
            })
            // some other stuff
            .asDriver(onErrorJustReturn: [])
        
        output = Output(sections: sections,
                        activityTracker: activityTracker, // <-- and here
                        errors: errorTracker) // <-- and here
    }
    
}

@andriy-appuchino
Copy link

andriy-appuchino commented Jun 10, 2020

I had to abandon the BaseViewModel class, as well as the parameters and functions of the SomeViewModel class that should be used in closures. And also the init function turns out to be rather cumbersome because nothing can be taken out of it into other functions without self.

I got something like this, but I'm not sure if this approach is suitable for all cases:

final class SomeViewModel: ViewModelType /* <-- protocol */ {
    
    let input: Input
    let output: Output

    struct Input {
        // nothing intresting
    }

    struct Output {
        let sections: Driver<[SectionModel<CellViewModel>]>
        let activityTracker: ActivityTracker
        let errors: ErrorTracker<Errors>
    }

    private let disposeBag = DisposeBag()

    override init() {
        let activityTracker = ActivityTracker() // <-- I can't declare it as a class parameter because I use it in closure where I can't use `self`
        let errorTracker = ErrorTracker<Errors>() // <-- the same
        input = Input()
        
        // prepare setCommand and selectCommand
        let sections = Observable.of(setCommand, selectCommand)
            .merge()
            .flatMap({ command -> Observable<Event<TableViewEditingCommand>> in
                switch command {
                case .setItems:
                    return Observable.just(command)

                case .selectItem(let indexPath):
                    return someUseCase.sendSomeRequest()
                        .trackActivity(activityTracker) // <-- `self` can't be used here
                        .map { command }
                        .asObservable()
                }
            })
            // some other stuff

        output = Output(sections: sections,
                        activityTracker: activityTracker,
                        errors: errorTracker)
    }
    
}

Maybe you have ideas how to improve it and avoid cumbersome?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment