Search code examples
iosnsstringuitextviewreactive-cocoa

How do I bind an NSString to a UITextView in Reactive Cocoa?


I'm building an iOS social client, and in the "compose" view, I've got a UITextView where the user enters text. I'd like to use ReactiveCocoa to bind the text of the UITextView to the NSString of the data model, to follow MVVM.

However, I'm running into several issues, all related to a single thing: the RACObserve block doesn't get called when the UITextView's text is changed programmatically.

(An example: I change the text into an attributed string to highlight #hashtags, @usernames, etc, but this attributed string doesn't get created when the view is programmatically changed.)

In my previous question on this topic, I got some helpful advice that I should bind the textview to the model - and vice versa - but it's not clear to me how I should do it with the current version of Reactive Cocoa. The sample code that I've managed to find calls APIs that are now deprecated.

What's the appropriate way to bind the rac_textSignal of a UITextView to an NSString (and vice versa) so that I can reliably call a block of code when the contents of the UITextView are changed (whether programmatically or by the user)?


Solution

  • The answer depends on whether the binding between the view model's text and the UITextViews text needs to be bidirectional. Generally we try to stay away from bidirectional bindings because they become harder to reason about. Ideally only one direction is driving the data.

    So in that case, you'd write something like:

    RAC(self.viewModel, text) = [RACSignal merge:@[ 
                                    [self.textView rac_textSignal], 
                                    RACObserve(self.textView, text),
                                ]];
    

    That way you're picking up on changes to both the UITextViews text property directly, and text changes that come from the user typing.