Swift自定义回调首次实例失效,二次实例正常问题排查
问题描述
我实现了一个自定义UIStackView组件TitleWithSwitchView,代码如下:
class TitleWithSwitchView: UIStackView { let title: String var onSwitchTapped: ((Bool) -> Void)? override init(frame: CGRect) { self.title = "" super.init(frame: frame) } required init(coder: NSCoder) { self.title = "" super.init(coder: coder) } init(title: String) { self.title = title super.init(frame: .zero) setupUI() setupConstraints() } private var label: UILabel { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = .white label.numberOfLines = 0 label.lineBreakMode = .byWordWrapping label.text = "-" return label } private lazy var labelTitle = { let label = label label.text = title return label }() private lazy var switchButton = { let switchButton = UISwitch() switchButton.translatesAutoresizingMaskIntoConstraints = false switchButton.addTarget(self, action: #selector(switchTapped), for: .valueChanged) return switchButton }() @objc private func switchTapped() { onSwitchTapped?(switchButton.isOn) } }
创建该组件的两个实例后,仅第二个实例的开关可正常响应点击,第一个实例点击无任何反应:
private lazy var stackViewHobbyContainer = { let stack = TitleWithSwitchView(title: "Some Text") stack.onSwitchTapped = { [weak self] isOn in self?.onHobbyContainerSwitchChange(isOn: isOn) } return stack }() private lazy var stackViewChallengeSwitchView = { let stack = TitleWithSwitchView(title: "Another Text?") stack.onSwitchTapped = { [weak self] isOn in print("Switch tapped \(isOn)") } return stack }()
问题分析与修复
核心原因
第一个实例的开关被标题标签挤压或遮挡,导致无法接收点击事件。你的标签设置了numberOfLines = 0(自动换行),在栈视图默认布局逻辑下,长文本的标签会优先占据可用空间,把开关挤出屏幕范围或完全遮挡;而第二个实例的标题文本较短,开关能正常显示,因此可正常响应。
修复步骤
- 完善
setupUI()方法(你之前的代码缺失了这部分关键布局逻辑):
private func setupUI() { // 将子视图添加到栈视图 addArrangedSubview(labelTitle) addArrangedSubview(switchButton) // 设置栈视图基础属性 axis = .horizontal spacing = 16 // 让标签和开关分别靠左右两侧排列,避免互相挤压 distribution = .spaceBetween alignment = .center // 给开关设置更高的水平内容优先级,确保其宽度不被压缩 switchButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) // 允许标签在空间不足时被压缩 labelTitle.setContentHuggingPriority(.defaultLow, for: .horizontal) }
- 简化标签创建逻辑,移除多余的
label计算属性:
private lazy var labelTitle: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = .white label.numberOfLines = 0 label.lineBreakMode = .byWordWrapping label.text = title return label }()
额外检查点
- 确认两个实例都已正确添加到父视图,且未被其他视图完全覆盖
- 检查
onHobbyContainerSwitchChange方法是否存在且逻辑正常,避免因闭包执行后无反馈,误以为开关未响应
内容的提问来源于stack exchange,提问作者Rahul Vyas
相关产品推荐
相关产品推荐

