设置UITextField.isSecureTextEntry致APP内存崩溃求助
问题根源与解决办法
嘿,我之前碰到过几乎一模一样的问题!你的APP冻结崩溃的核心原因是**layoutSubviews方法陷入了无限递归循环**,而isSecureTextEntry = true的场景刚好触发了这个循环的爆发。
为什么会这样?
咱们拆解一下触发链:
- 当你设置密码框为安全输入模式,按下回车调用
resignFirstResponder()时,UITextField的内部状态和布局会发生额外变化(比如安全文本的视觉切换、输入状态重置),这会触发系统调用layoutSubviews。 - 你的
Textfield子类在layoutSubviews里调用了setupTextfield(),而这个方法里直接修改了self.frame.size.height = self.height——修改视图的frame会再次触发系统调用layoutSubviews,形成无限递归。 - 内存会在这个无限循环里被疯狂消耗,直到系统因为内存不足终止APP;而
isSecureTextEntry = false时,回车收起键盘的过程中没有触发额外的布局更新,所以循环没被激活,看起来一切正常。
解决办法:停止在layoutSubviews里修改frame
layoutSubviews是系统用来通知视图更新布局的回调,绝对不能在这个方法里修改视图的frame、bounds或者触发布局变化的属性,否则必然会引发循环。我们可以把布局相关的初始化移到初始化方法里,改用Auto Layout或者仅在初始化时设置frame:
方案1:移到初始化方法(适配代码创建场景)
修改你的Textfield子类,把高度设置和初始化逻辑放到统一的初始化方法里:
@IBDesignable class Textfield: UITextField { let padding: UIEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15) let height: CGFloat = 60 let cornerRadius: CGFloat = 15 override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { // 初始化时设置高度,只执行一次 self.frame.size.height = self.height // 初始化样式和其他配置 setupTextfield() } override func layoutSubviews() { super.layoutSubviews() // 这里只做需要实时响应布局变化的操作,比如根据编辑状态切换背景色 self.backgroundColor = isEditing ? Constants.Colors.light_white : Constants.Colors.light_grey // 其他需要在布局更新时同步的样式也可以加在这里,但绝对不要修改frame! } private func setupTextfield() { // style self.styleTextfield() // correction self.autocorrectionType = .no } private func styleTextfield() { // font self.font = UIFont.systemFont(ofSize: 17) // color self.textColor = Constants.Colors.dark_blue.withAlphaComponent(0.6) // alignment self.contentVerticalAlignment = .center // default background self.backgroundColor = isEditing ? Constants.Colors.light_white : Constants.Colors.light_grey // border self.borderStyle = .none // corners self.layer.cornerRadius = self.cornerRadius // shadow self.layer.shadowColor = UIColor.black.cgColor self.layer.shadowOpacity = 0.1 self.layer.shadowOffset = CGSize(width: 0, height: 3) } // 其他重写方法保持不变... }
方案2:用Auto Layout约束高度(更推荐,适配Storyboard/XIB场景)
如果你是用Storyboard或者XIB创建的文本框,更推荐用Auto Layout来固定高度,避免直接修改frame:
private func commonInit() { // 关闭自动转换约束,手动添加约束 translatesAutoresizingMaskIntoConstraints = false // 添加高度约束 NSLayoutConstraint.activate([ self.heightAnchor.constraint(equalToConstant: height) ]) setupTextfield() }
这样修改后,按下回车收起键盘时,layoutSubviews只会执行必要的布局更新,不会触发无限循环,内存问题就彻底解决了。
内容的提问来源于stack exchange,提问作者Lukas
相关产品推荐
相关产品推荐

