7

I would like to create a property wrapper which is invalidating the layout of my UICollectionViewLayout.

Therefore I created this property wrapper

@propertyWrapper
class LayoutInvalidating {
    private let layout: UICollectionViewLayout

    init(layout: UICollectionViewLayout) {
        self.layout = layout
        self.wrappedValue = layout
    }

    var wrappedValue: UICollectionViewLayout {
        didSet {
            self.layout.invalidateLayout()
        }
    }
}

Then I would like to use it as follows

final class VehicleControlsCollectionViewLayout: UICollectionViewLayout {
     @LayoutInvalidating(layout: self) // self is not alive
     public var itemSize: CGSize = .init(width: 70, height: 70)
}

Everytime the property is set I would like to call self.invalidateLayout(). Any ideas how I can access self when it's existing?

BilalReffas
  • 8,132
  • 4
  • 50
  • 71

1 Answers1

6

Unfortunately, it is not possible to add self to @propertyWrappers init - this property is create during creation of self.

It will be possible in the future - look at proposal (Referencing the enclosing 'self' in a wrapper type).


If you are looking for some kind of workaround, you can consider add function to your property wrapper and call this function after init in your class:

@propertyWrapper
class LayoutInvalidating<Value> {
    private var layout: UICollectionViewLayout?

    init(wrappedValue: Value) {
        self.wrappedValue = wrappedValue
    }

    func configure(with layout: UICollectionViewLayout?) {
        self.layout = layout
    }

    var wrappedValue: Value {
        didSet {
            layout?.invalidateLayout()
        }
    }
}

final class VehicleControlsCollectionViewLayout: UICollectionViewLayout {
    @LayoutInvalidating
    public var itemSize: CGSize = .init(width: 70, height: 70)

    override init() {
        super.init()
        _itemSize.configure(with: self)
    }
}
Michcio
  • 2,708
  • 19
  • 26