You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift子类化UIStackView时使用weak属性引发崩溃的原因

问题出在Weak引用的生命周期上

兄弟,你遇到的崩溃完全是对weak修饰符的理解偏差导致的,咱们一步步拆解:

当你把container和titleLabel改成weak后,执行container = UIView()这行代码时,新创建的UIView实例没有任何强引用持有它——weak变量本身不会增加对象的引用计数,所以这行代码执行完的瞬间,这个UIView就被ARC(自动引用计数)立即回收了,container也就变成了nil。接下来你再去访问container.backgroundColor,自然就触发了“解包nil可选值”的致命错误。

为什么原来的非Weak版本没问题?

原来的代码里,container是强引用变量,它会持有新创建的UIView实例,直到你执行addArrangedSubview(container)——这时候UIStackView的arrangedSubviews数组会对这个container视图持有强引用。也就是说,此时有两个强引用指向container:一个是你的自定义StackView的container属性,另一个是StackView内部的数组。这样container的生命周期就和StackView绑定了,不会提前释放。

关于你担心的引用循环——其实完全没必要

你怕自定义StackView和子视图形成循环引用?放心,iOS视图层级的引用关系是父视图强引用子视图,子视图弱引用父视图:

  • 你的自定义StackView(父)强引用container(子)
  • container的superview属性是weak的,指向你的StackView
  • 同理,container强引用titleLabel,titleLabel的superview是weak指向container

这种结构根本不会形成循环引用,所以你完全不需要给这些子视图属性加weak修饰符。

正确的做法

直接把weak修饰符去掉,保持原来的强引用即可:

class UIButtonHeaderView: UIStackView {
    // MARK: - Properties
    var container: UIView!
    var titleLabel: UILabel!

    // MARK: - Initialization
    private func setUp() {
        // Set container.
        container = UIView()
        container.backgroundColor = .blue
        addArrangedSubview(container)

        // Set label.
        titleLabel = UILabel()
        container.addSubview(titleLabel)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
        titleLabel.bottomAnchor.constraint(equalTo: container.bottomAnchor).isActive = true
        titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: container.trailingAnchor).isActive = true
        titleLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
        titleLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
        titleLabel.text = "This is just a simple test!!"
        titleLabel.backgroundColor = .green
        titleLabel.textColor = .red
        titleLabel.sizeToFit()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setUp()
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        setUp()
    }
}

这样修改后,container和titleLabel的生命周期会和你的自定义StackView保持一致,既不会提前释放导致崩溃,也不会产生循环引用的内存问题。

内容的提问来源于stack exchange,提问作者Nestarneal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:03:07