【问题标题】:Weak property for subclassing UIStackView in iOS Swift在 iOS Swift 中继承 UIStackView 的弱属性
【发布时间】:2018-10-26 12:58:36
【问题描述】:

我尝试继承 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!

我认为类UIButtonHeaderView及其属性(container和titleLabel)的实例可能存在引用循环问题,所以我尝试在var前面添加weak,导致我的App崩溃。

Xcode 告诉我这一行

container.backgroundColor = .blue

错误信息出错了

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

好像行

container = UIView()

创建UIView类的实例失败,所以container为nil,导致App崩溃,不知道是什么原因。

【问题讨论】:

  • 不相关的注意:你通常不应该在这里继承UIStackView。你应该继承UIView 并添加一个UIStackView。这并不是真正的“一种堆栈视图”(IS-A)。这是一个标题视图,恰好使用堆栈视图进行布局(HAS-A)。您通常应该避免子类化不是为它设计的 UIKit 类(如果它是为子类设计的,那么文档通常会包含“子类化注释”之类的部分或以其他方式讨论子类化)。
  • 另外,你应该避免使用UI 前缀作为你的类名;它会起作用,但你的类不是 UIKit 的一部分,所以它违反了约定。

标签: ios swift uilabel uistackview subclassing


【解决方案1】:

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

当你这样说时:

container = UIView()

新创建的视图没有强引用,因此它会立即被释放,container 将在您有机会将其添加到堆栈视图之前变为nil

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

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

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

【讨论】:

    【解决方案2】:

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

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

    意味着(通过weak)如果对象被释放,你希望这个值变成nil,并且(通过!)你保证如果它是nil,你将永远不会访问它。这些是相互矛盾的。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2014-11-10
        • 2016-10-18
        • 1970-01-01
        • 2017-12-18
        • 2014-02-03
        • 2012-05-08
        • 1970-01-01
        • 1970-01-01
        • 2011-06-13
        相关资源
        最近更新 更多