【问题标题】:Property Wrappers: "Cannot use instance member within property initializer; property initializers run before 'self' is available"属性包装器:“不能在属性初始化器中使用实例成员;属性初始化器在‘self’可用之前运行”
【发布时间】:2020-06-18 22:23:20
【问题描述】:

我正在尝试创建波纹管属性包装器

@propertyWrapper
public struct ConstraintValue {

    private let view:UIView
    private let contraint:NSLayoutConstraint

    public init(contraint:NSLayoutConstraint,view:UIView) {
        self.contraint = contraint
        self.view = view
    }

    public var wrappedValue: CGFloat {
        set {
            contraint.constant = newValue
            view.layoutIfNeeded()

        }

        get {
            return contraint.constant
        }

    }
}

但是当我尝试使用它时,我得到“不能在属性初始化器中使用实例成员;属性初始化器在 'self' 可用之前运行”

@IBOutlet weak private var imageViewHeightConstraint: NSLayoutConstraint!
 @ConstraintValue(contraint: imageViewHeightConstraint, view: self)
 public var imageHeight:CGFloat

有没有办法解决这个错误?

【问题讨论】:

  • 你能展示更多声明imageHeight的类吗?具体来说,imageViewHeightConstraint是如何初始化的?
  • @IBOutlet 弱私有变量 imageViewHeightConstraint:NSLayoutConstraint!它是一个 IBOutlet
  • 制作属性lazy
  • 哪个属性?

标签: ios swift property-wrapper


【解决方案1】:

你不能使用selfimageViewHeightConstraint来初始化这个属性,因为它现在不存在。

最简单的解决方案是在视图的init() 方法中将约束和视图传递给包装器,如下所示:

@propertyWrapper
public struct ConstraintValue {

    var view: UIView!
    var constraint: NSLayoutConstraint!

    public var wrappedValue: CGFloat {
        set {
            constraint.constant = newValue
            view.layoutIfNeeded()

        }

        get {
            return constraint.constant
        }
    }
}

class OurView: UIView {

    var imageViewHeightConstraint: NSLayoutConstraint!

    @ConstraintValue public var imageHeight:CGFloat

    init() {
        super.init(size: .zero)
        _imageHeight.view = self
        _imageHeight.constraint = imageViewHeightConstraint
    }
}

或者,您可以将 KeyPath 用于imageViewHeightConstraint,并将self 传递给视图init() 中的属性包装器。像这样的:

protocol DynamicImageView: UIView {
    var imageViewHeightConstraint: NSLayoutConstraint! { get set }
}

@propertyWrapper
public struct ConstraintValue {

    var view: DynamicImageView?
    private let constraintKeyPath: WritableKeyPath<DynamicImageView, NSLayoutConstraint>

    init(constraintKeyPath: WritableKeyPath<DynamicImageView, NSLayoutConstraint>) {
        self.constraintKeyPath = constraintKeyPath
    }

    public var wrappedValue: CGFloat {
        set {
            view?[keyPath: constraintKeyPath].constant = newValue
            view?.layoutIfNeeded()
        }

        get {
            view?[keyPath: constraintKeyPath].constant ?? 0.0
        }
    }
}

class OurView: UIView, DynamicImageView{

    var imageViewHeightConstraint: NSLayoutConstraint!

    @ConstraintValue(constraintKeyPath: \.imageViewHeightConstraint)
    public var imageHeight:CGFloat

    init() {
        super.init(frame: .zero)
        _imageHeight.view = self
    }
}

【讨论】:

  • 感谢您的回复。有没有办法在不通过它的情况下访问视图?
  • @ChristosChadjikyriacou 您可以在某种容器视图中拥有此属性,并使其更改其中一个子视图中的约束,但最终这对于属性包装器来说并不是很好的情况。使用属性观察器 (didSet) 会更容易,因为您无需初始化结构即可使其工作。
猜你喜欢
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
相关资源
最近更新 更多