1

As I'm creating a custom UITextField, i.e. CurrencyTextField as per How to input currency format on a text field (from right to left) using Swift?. I could set the configuration in willMove function as below

    override func willMove(toSuperview newSuperview: UIView?) {
        Formatter.currency.locale = locale
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        keyboardType = .numberPad
        textAlignment = .right
        sendActions(for: .editingChanged)
    }

However, as I previously learn, we could also set it during init as below instead of using willMove

    override init(frame: CGRect) {
        super.init(frame: frame)
        Formatter.currency.locale = locale
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        keyboardType = .numberPad
        textAlignment = .right
        sendActions(for: .editingChanged)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

They seems to behave the same for my case. So I'm not sure when should I use init, and when should willMove?

I saw this post on deinit vs willMove in Why is deinit not called until UIView is added to parent again?. That's well explained for deinit vs willMove, but not clear my question on init vs willMove

Elye
  • 53,639
  • 54
  • 212
  • 474

1 Answers1

4

willMove can be called multiple times (whenever the view's super view changes). init is only called once ever.

The main question for you to consider is:

Do you want your code to run only once, or every time the view's super view changes?

For example, the below code will print will move called three times:

class MyView: UIView {
    override func willMove(toSuperview newSuperview: UIView?) {
        print("will move called")
    }
}

let view1 = UIView()
let view2 = UIView()
let myView = MyView()
view1.addSubview(myView) //*
myView.removeFromSuperview() //*
view2.addSubview(myView) //*

Every line marked with * will cause willMove to be called. Note that even removing the view from its superview calls willMove, since it "moves to a new super view of nil".

For your specific case though,

Formatter.currency.locale = locale
addTarget(self, action: #selector(editingChanged), for: .editingChanged)
keyboardType = .numberPad
textAlignment = .right
sendActions(for: .editingChanged)

I don't think executing the above code more than once makes much of a difference, so putting it in either method works fine.


Another difference is that init is called immediately after the view is created, while the first call of willMove does not happen until the view is added to a superview. This might make a difference in some rare cases.

Sweeper
  • 213,210
  • 22
  • 193
  • 313