在 iOS Swift 中子类化 UIStackView 的弱 属性

Weak property for subclassing UIStackView in iOS Swift

我尝试子class UIStackView 并添加一些我想要的控件。我添加一个 UIView 作为容器,所有其他视图,如 UILabel、UIButton、UIImageView 等,将作为子视图添加到容器中。

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()
    }
}

代码没问题,但是替换的时候遇到了问题

var container: UIView!
var titleLabel: UILabel!

weak var container: UIView!
weak var titleLabel: UILabel!

我觉得classUIButtonHeaderView的实例和它的属性(container和titleLabel)可能有引用循环问题,所以我尝试在var前面加上weak,导致我的App崩溃.

Xcode 告诉我这一行

container.backgroundColor = .blue

错误信息出错

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

好像行

container = UIView()

创建classUIView实例失败,所以container为nil,导致App crash,不知道是什么原因

你必须创建可选项,因为当我们有一个 属性 持有对对象的弱引用时,它的类型应该是可选的,因为它有能力在运行时变为 nil。

weak var container: UIView?
weak var titleLabel: UILabel?

为了扩展 Khushbu 的回答,这个:

weak var container: UIView!
weak var titleLabel: UILabel!

表示(通过 weak)如果对象被释放,您希望此值变为 nil,并且(通过 !)您保证永远不会访问它如果是nil。这些是相互矛盾的。

要扩展 Rob 的回答,如果您将属性设为 weak 可选,您仍然会遇到问题。

当你这样说时:

container = UIView()

新创建的视图没有强引用,所以它会立即被释放并且container会变成nil,然后你才有机会将它添加到stackview。

要解决这个问题,您需要使用局部变量来保存 UIView 引用,直到它被添加为子视图;此时,堆栈视图将持有一个强引用,您可以将引用分配给您的 weak 属性 并让局部变量超出范围而不释放视图。

let newContainer = UIView()
newContainer.backgroundColor = .blue
addArrangedSubview(newContainer)
container = newContainer

我同意 Rob 的评论; subclassinf UIStackView 在这里可能不是正确的方法。