0

我现在正在用 Swift 编写自定义 UITextField,并遇到以下情况:

class MyField: UITextField {
    
    open override var text: String? {
        didSet {
            // some logic that normalizes the text
        }
    }

    private func setup() { //called on init
        addTarget(self, action: #selector(textEditingChanged(_:)), for: .editingChanged)
    }

    @objc func textEditingChanged(_ sender: UITextField) {
    }
}

现在,在对此进行测试时,我观察到,当用户输入内容时,textEditingChanged会调用它,但text.didSet不会调用。也不是text.willSet,就此而言。但是,在 中textEditingChanged,文本字段的文本将已更新为新值。

谁能解释这里发生了什么?斯威夫特是故意绕过二传手吗?我应该如何知道何时/是否调用了 setter,在 UIKit 中是否有任何逻辑?

4

2 回答 2

2

的 text 属性UITextField仅供外部使用,当您键入时会UIKit在内部处理更新。无法真正说出幕后发生的事情,因为我们无权访问UIKit实现,但问题的一个可能答案UITextField是使用另一个内部变量来存储 text 属性。当您获取 text 属性时,实际上是在获取该内部值,而在设置它时,您也在设置该内部值。当然,在引擎盖下它有点复杂,但它可能看起来像这样(SampleUITextField代表UITextField):

// This how the UITextField implementation may look like
class SampleUITextField {
    private var internalText: String = ""

    var text: String  {
        get {
            internalText
        } set {
            internalText = newValue
        }
    }

    // This method is just to demonstrate that when you update the internalText didSet is not called 
    func updateInternalTextWith(text: String) {
       internalText = text
    }
}

当您将其子类化时,它看起来像:

class YourTextField: SampleUITextField {
    override var text: String {
        didSet {
            print("DidSet called")
        }
    }
}

现在,当您直接设置 text 属性时,didSet会调用它,因为text值会更新。你可以检查它:

let someClass = YourTextField()
someClass.text = "Some new text"
// didSet is called 

但是现在当你调用时updateInternalTextWith不会didSet调用:

let someClass = YourTextField()
someClass.updateInternalTextWith(text: "new text")
// didSet is not called 

那是因为您没有直接更新文本值,而只是更新内部文本属性。UITextField键入时调用类似的方法来更新内部文本变量,这didSet就是在您的情况下不调用的原因。

text出于这个原因,当我们想要在文本属性发生变化时得到通知时,仅仅覆盖变量是不够的,我们需要使用delegate( UITextFieldDelegate)方法或notifications( textFieldDidChange)来捕捉实际的变化。

于 2021-03-29T12:17:40.820 回答
0

你想在 UITextField 上执行什么样的格式?

它不应该由ViewModel(或管理包含此文本字段的视图的业务逻辑的任何模型)负责吗?

此外,您不应该使用didSet来执行更改,它主要是为了让您响应更改,而不是链接另一个更改。

于 2021-03-29T11:43:26.073 回答