This repository contains two quite complex bugs related to the memory management of text fields in SwiftUI that I recently discovered.
Fortunately, I was only able to reproduce it on simulators. However, maybe there is also a way to reproduce it on a physical device.
This issue is reproducible only on simulators. Confirmed on iOS 14.5 and 16.4.
It took me a while to figure out what's going on but here are the steps:
- Create a
View
with twoTextField
s in aVStack
. - Navigate to that
View
. - Tap the first
TextField
(it might not be necessary). - Go back to the previous screen.
Even if you leave the screen, TextField
s will be still in memory. What's even worse, if you have a binding in your View
with TextField
s, the reference will be kept as well. Therefore, if you bind to a view model, it won't be released.
TextField
s should be released as soon as you leave the screen including bindings to a view model.
- Run it on a physical device.
- Use just one
TextField
per screen ¯_(ツ)_/¯.
This problem is a little bit more tricky to reproduce, but if you have to deal with iOS 14 and custom focus management, it is quite likely that you will encounter this problem sooner or later.
This issue is reproducible on simulators and physical devices. Confirmed on iPhone 12 Pro with iOS 16.5 and on simulators with iOS 14.5, 15.5, and 16.4.
- Use a custom text field implemented using
UIViewRepresentable
. - Make sure to set a keyboard type to
numberPad
. - Show your
TextField
with animation. - Call ONCE
uiView.becomeFirstResponder()
fromUIViewRepresentable
before theTextField
is visible.
As you can see, this is indeed a series of unfortunate events, but it makes this issue even more dangerous. Potentially unrelated changes may trigger this problem.
Even if you leave the screen, TextField
will be still in the memory. If you have a binding in the View
with TextField
the reference will be kept as well. Therefore, if you bind to a view model, it won't be released.
If you check the memory graph, you will see that the reference to the TextField
is kept by UIKBAutofillController
.
TextField
s should be released as soon as you leave the screen including bindings to a view model.
There are multiple ways not to fall into this specific bug:
- Change the keyboard type to a different one, for example:
.default
. - Avoid starting the screen with hidden
TextField
. - Avoid custom focus implementations.
- Don't call
becomeFirstResponder()
when the screen appears. - Disable Autofill feature in Settings -> Passwords -> Password Options -> AutoFill Passwords.
- After leaving the screen, tap on a different text field. The keyboard will release the reference to the previous one.
These issues have been reported to Apple: #FB12224488. 🤔 This ID seems to be very "random".
Anyway, probably no one from Apple will ever read this bug, that's why I decided to describe it here.