0

I have a ViewModel where an service class is defined, This service class is initialized in this ViewModel's initializer. Now I need to update my View when there is any change in its value in ViewModel(getting it from service). Although I have found some examples of using Variable but I could not find it with Class injection. ViewController:

    var presenter:Variable<CardViewModelProtocol>!
        func setPresenter() {
//Following line has error
            self.presenter = Variable<CardViewModelProtocol>(CardViewModelProtocol(service:CardService()))
            self.presenter.value.attachView(view: self)
        }

the line where presenter is initialized is giving error. Error:

'CardPresenterProtocol' cannot be constructed because it has no accessible initializers

Following is how the ViewModel initialized:

var cardService:CardServiceContract!
var materialNum = Variable<String>("")

init(service:CardServiceContract){
    self.cardService = service
}

Edit1: In short I want to convert following line to RxSwift supporting Variables and observe a variable(class object) in CardViewModel:

self.presenter = CardViewModel(service: CardService())

Edit2:

    protocol CardViewModelProtocol : BaseViewModelProtocol {

    func loadCardInfo(Serial serial:String)

    var materialNum: Variable<String> {get set}
}
protocol BaseViewModelProtocol {
    func attachView(view: BaseViewProtocol)
}
protocol BaseViewProtocol{
    func setViewModel()
}
pankaj
  • 7,878
  • 16
  • 69
  • 115
  • Variables will be deleted in future version of RxSwift. Also it is really bad practice to init Variable with some constructor. This breaks the purpose of Reactive programing. Why don't you pass the actual reference of CardService object? I don't see any point of creating variable like this. You should at least pass the value not construct it. – Dominik Bucher Feb 01 '18 at 10:56
  • So what should I use in place of Variables? can you please suggest me the best practice here?, I have just started using RxSwift – pankaj Feb 01 '18 at 10:59
  • Please provide more information about your 3 classes. (Show CarService and probably CardViewCOntroller) – Dominik Bucher Feb 01 '18 at 11:20
  • I have added all my relevant code here, there is one more method in ViewModel which will get some data from CardService, when this ViewModel receives this data(string), it will bind it to materialNum in ViewModel and send it to View to display – pankaj Feb 01 '18 at 11:27
  • So in a nutshell View will call ViewModel, it will then call Service, Service will then return data to ViewModel which will then return it to ViewController, if you can point me to some example like this it will be great – pankaj Feb 01 '18 at 11:33
  • You do not have relevant things in here - I don't see the CardViewModelProtocol class which has bad naming and maybe because it is protocol you cannot initialise :) – Dominik Bucher Feb 01 '18 at 11:36
  • Please check my Edit2 – pankaj Feb 01 '18 at 11:52
  • Now tell me how do you want to construct Protocol. – Dominik Bucher Feb 01 '18 at 12:01
  • I just want a simple flow, view makes a request to viewmodel for some data, viewmodel will call service and ask it to fetch it from web service. Now web service should return it to ViewModel which will return it to ViewController and then it will be displayed. If you can suggest best approach here it will great. – pankaj Feb 01 '18 at 12:05
  • How do you construct protocol in Swift? – Dominik Bucher Feb 01 '18 at 12:10
  • you can see it in my Edit2 – pankaj Feb 01 '18 at 12:27
  • Maybe this can help you https://stackoverflow.com/questions/34801399/protocol-extension-initializer – Dominik Bucher Feb 01 '18 at 12:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164337/discussion-between-dominik-bucher-and-pankaj). – Dominik Bucher Feb 01 '18 at 12:32
  • The question was in general, not in your code: How do you construct the protocol in any programming language? – Dominik Bucher Feb 01 '18 at 13:42
  • 4.0.0 "Deprecates Variable in favor of BehaviorRelay." – Maxim Volgin Feb 01 '18 at 14:23

1 Answers1

0

This is an example of usage - https://github.com/RxSwiftCommunity/RxSegue/blob/master/Example/RxSegue/ProfileViewController.swift

But keep in mind that RxSwift 4.0.0 "Deprecates Variable in favor of BehaviorRelay."

If you are not obliged to follow MVVM, you can try unidirectional dataflow approach instead - https://github.com/maxvol/RaspSwift

In case to have a continuous subscription to server updates, you can use .switchLatest() operator like that -

let stream = PublishSubject<Observable<Response>>()
stream.switchLatest().subscribe(consumer)
stream.onNext(serverRequestReturningResponseObservable) // repeat whenever needed
Maxim Volgin
  • 3,957
  • 1
  • 23
  • 38