4

I'm implementing ReactiveCocoa 4 in an as-basic-as-possible iOS app (Swift), in order to get a better idea of how to use it with MVVM architecture. My question is: how do I get a UITextField's textSignal from the view up to the model?

What I've got here works, but it feels like this is only 50% reactive (and not too pretty in any case):

VIEW (in viewDidLoad)

originalTextField.rac_textSignal().subscribeNext{
    (next:AnyObject!) -> () in
    let text = next as! String
    self.viewModel?.originalText=text
}

VIEW MODEL

var originalText:String?{
    didSet{self.model.originalText=originalText}
}

MODEL

var originalText:String?{
    didSet{//Do model stuff}
}
Rogare
  • 3,234
  • 3
  • 27
  • 50

1 Answers1

0

This is how I currently implement this behavior, I'm fairly new to RAC as well so take it with a grain of salt.

I'm using ReactiveCocoa 4.1.0 & Rex 0.10.0


ViewModel:

  1. Set a MutableProperty for originalText

Mutable properties have a producer property that you will bind to from your view.

With that bound, calling originalText.producer.startWithNext will create a Signal and add 1 observer so you'll be able to receive values from within your ViewModel

    let originalText: MutableProperty<String> = MutableProperty("")

    func observeTextField(){
        originalText.producer.startWithNext { (str) in
            self.model.originalText = str
        }
    }

View:

Add Rex as a dependency and import it. You'll be using ignoreError from Rex to handle a type conflict.

SignalProducer is defined as SignalProducer<T, ErrorType> so you'll have to drop the ErrorType to match your MutableProperty<String>.

  1. Create a signal producer from the textfield
  2. Ignore the error on the signal producer
  3. Bind the signal producer to your ViewModel's MutableProperty
  4. Call ViewModel.observeTextField from the the view after the binding from step 3

The infix <~ operator binds the producer to your ViewModel's MutableProperty

    import Rex

...

    let textFieldProducer = (originalTextField.rac_textSignal()
        .toSignalProducer()
        .map {text in text as! String}
        .ignoreError())!

    viewModelInstance.originalText <~ textFieldProducer

I hope this helps you.