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

Swift中声明UIStackView属性时为何需要使用lazy var?

异常运行效果截图

以下是自定义UITableViewCell的实现代码:

class SummaryLabelTVC: UITableViewCell {
    static let identifier = "SummaryLabelTVC"

    var summaryIcon = UIImageView().then {
        $0.image = UIImage(systemName: "calender")
        $0.tintColor = UIColor.white
    }

    var label = UILabel().then {
        $0.font = .systemFont(ofSize: 13)
        $0.textColor()
    }

    lazy var stackView = UIStackView().then {
        $0.axis = .horizontal
        $0.alignment = .leading
        $0.addArrangedSubview(summaryIcon)
        $0.addArrangedSubview(label)
    }

    private func configureUI() {
        addSubview(stackView)
        addSubview(label)
    }
}

上述实现中summaryIcon、label均用普通var声明,仅stackView用lazy var声明,将stackView的lazy关键字移除改为普通var后,就出现截图中的异常效果。

核心原因

两类属性声明的核心差异是初始化时机不同:

  • 普通var存储属性:在类实例两段式初始化的第一阶段完成赋值,赋值时self尚未完成构造,此时不能在属性的默认初始化逻辑中引用同实例的其他属性、调用和self相关的方法,否则会出现初始化顺序混乱、拿到未初始化的无效值。
    代码里的summaryIcon和label初始化逻辑只修改自身属性,没有引用其他实例属性,所以用普通var完全没问题。
  • lazy var存储属性:第一次被代码访问时才会执行初始化逻辑,初始化时类实例已经完成全部构造,self状态完整可用,可以正常引用实例上的其他属性、调用实例方法。
    代码里的stackView初始化时需要调用addArrangedSubview把同实例的summaryIcon、label加到自身上,必须依赖完整可用的self,所以直接用普通var会因为初始化阶段self未完成构造,无法正确获取两个子视图的有效实例,最终出现布局异常。
额外代码问题

代码里还有两个和lazy关键字无关、但会直接导致布局错乱的问题:

  1. UITableViewCell的所有自定义子视图必须添加到contentView上,不能直接调用addSubview加到cell根视图,否则会出现滑动时布局错位、手势交互异常的问题。
  2. configureUI方法里在添加stackView之后,又单独执行了addSubview(label):UIKit规定同一个视图同时只能有一个父视图,被addSubview到新父视图时会自动从原父视图移除。这行代码会直接把label从stackView的视图层级里移出,单独挂在cell根视图上,导致stackView里只剩icon,布局完全错乱,这行多余代码必须删除。

另外代码还有两处语法/拼写错误:

  • 系统日历图标名称拼写错误,正确是calendar,写的calender会导致图片加载失败
  • label初始化里的$0.textColor()是错误的方法调用,textColor是属性,需要直接赋值,比如$0.textColor = .label
修正参考代码
class SummaryLabelTVC: UITableViewCell {
    static let identifier = "SummaryLabelTVC"

    var summaryIcon = UIImageView().then {
        $0.image = UIImage(systemName: "calendar")
        $0.tintColor = .white
    }

    var label = UILabel().then {
        $0.font = .systemFont(ofSize: 13)
        $0.textColor = .label
    }

    lazy var stackView = UIStackView().then {
        $0.axis = .horizontal
        $0.alignment = .leading
        $0.spacing = 8
        $0.addArrangedSubview(summaryIcon)
        $0.addArrangedSubview(label)
    }

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        configureUI()
    }

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

    private func configureUI() {
        contentView.addSubview(stackView)
        // 按需设置布局约束,示例为SnapKit写法
        stackView.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16))
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:57:20