RxSwift: Japanese text would be broken if UITextField has two-way-binding ControlProperty and Variable.

I use two-way-binding operator UITextField.rx_text and Variable like RxExample. https://github.com/ReactiveX/RxSwift/blob/master/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift#L142-L149

And please see this capture.  I want to input “あいうえお” at the textField, but we can see a wrong text “ああいあいうあいうえあいうえお”. I believe ControlProperty should not receive event about the value inputted from user, because textField would lost the invisible state when set the same text.

And UITextView has the nearly same problem. In UITextView, we cannot use IME character conversion.

This problem would occur in every language that has IME.

I believe the easy way to solve this problem is change the implements of two-way-binding operator. But… I think ControlProperty(or rx_value) might check the observed value is not equal to a value inputted from user.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 24 (13 by maintainers)

Commits related to this issue

Most upvoted comments

Hi guys,

That’s an interesting discussion for sure 😃

It seems to me that adding something like

/**
    Reactive wrapper for `text` property. Notifications are fired only when when there
    isn't any marked text.
    */
    public var rx_nonMarkedText: ControlProperty<String> {
        let textProperty = self.rx_text
        return ControlProperty(
            values: textProperty._values.filter { [weak self] _ in self?.markedTextRange == nil },
            valueSink: textProperty._valueSink
        )
    }
         let textValue = Variable("")
        textField.rx_nonMarkedText <-> textValue

        textValue.asObservable()
            .subscribeNext { [weak self] x in
                self?.debug("UITextField text \(x)")
            }
            .addDisposableTo(disposeBag)

would solve your problems. I don’t understand the full culture/language context so if you could provide feedback, that would be great.

@Succete Thank you for a suggestive report. I was able to reproduce it, and tap to “愛” in conversion candidates. Then fields presents “ああい愛”. Keyboard may replace undetermined text in UITextView to its determined conversion result in ordinary cases. If we set UITextView.text, undetermined text is cleared and selecting with blue shadow is reset. So conversion result is just appended without replacing.

@omochi Thanks for your explain, yes it is just my thinking.

@Succete Yes, I believe we can fix two-way-binding operator, and It is easy way to solve this problem. On the other hand, I worry about specification of ControlProperty. “ControlProperty should (or not) receive event that is notified ownself.”

I try it too. And I found an interesting result.

first case:

textField.rx_text
            .debug("text")
            .subscribeNext { text in
                print(text)
            }
            .addDisposableTo(disposeBag)

It’s true.

second case

let textValue = Variable("")
        textField.rx_text <-> textValue

        textValue.asObservable()
            .subscribeNext { text in
                print(text)
            }
            .addDisposableTo(disposeBag)

        textField.rx_text
            .subscribeNext { text in
                print(text)
            }
            .addDisposableTo(disposeBag)

they are both false.

and there are snapshots first case simulator screen shot 2016 4 28 11 49 50 second case simulator screen shot 2016 4 28 11 50 28

It seems that in first case keyboard is waiting my confirm, but second case not. I think maybe the <-> operator is the reason for the bug. let bindToUIDisposable = variable.asObservable() .bindTo(property) this code bind variable’s value to property. When I type “あ”, the value has been set to property(but it should wait for my confirm before it is set).

I try to explain more detail of @tarunon said. UITextField have internal two variable which are determined text and undetermined text. This treats .text property as their concatenation. If we update .text property, it updates determined text and clear undetermined text. The keyboard remembers previous text user inputted and recover this from memory when user input next character. This behavior is need to conversion such like “あい”(hiragana) to “愛”(kanji). For evidence, “愛” is shown in conversion candidates on top of keyboard in his GIF movie.

So his scenario is able to written as below.

First state. (.text: "", det: "", undet: "", keyboard: "") When user inputs “あ”, keyboard set undet text to textview. (.text: "あ", det: "", undet: "あ", keyboard: "あ") .text is “あ”, so ControlProperty emits “あ” A emitted “あ” loopbacks and set to .text. In this point, the keyboard reminders previous “あ” but does not apply it to textview until user changes keyboard state. (.text: "あ", .det: "あ", undet: "", keyboard: "あ") Then user inputs “い”, keyboard updates textviews undet text. (.text: "ああい", .det: "あ", undet: "あい", keyboard: "あい")

@tarunon Is my understanding same to you?