Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access self in Swift 5.1 Property Wrappers

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?

like image 335
BilalReffas Avatar asked Sep 24 '19 11:09

BilalReffas


People also ask

How do you use property wrapper in Swift?

This property can have any type you want. To access this property, you need to add a $ prefix to the property name. To explain how it works, we use an example from the Combine framework. The @Published property wrapper creates a publisher for the property and returns it as a projected value.

How do I make a property wrapper?

You can create a Property Wrapper by defining a struct and marking it with the @propertyWrapper attribute. The attribute will require you to add a wrappedValue property to provide a return value on the implementation level.

What is wrappedValue in Swift?

The underlying value referenced by the binding variable.

What is @published SwiftUI?

@Published is one of the property wrappers in SwiftUI that allows us to trigger a view redraw whenever changes occur. You can use the wrapper combined with the ObservableObject protocol, but you can also use it within regular classes.


1 Answers

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)
    }
}
like image 120
Michcio Avatar answered Oct 20 '22 08:10

Michcio