Difference Between @Propertydelegate and @Propertywrapper

Difference between @propertyDelegate and @propertyWrapper

TLDR; they are the same but you should use @propertyWrapper.

As pointed out by @JosefDolezal on twitter https://twitter.com/josefdolezal/status/1137619597002248192?s=21, the name @propertyDelegate was returned for revision by the core team https://forums.swift.org/t/returned-for-revision-se-0258-property-delegates/24080. The core team proposed multiple alternative namings, but because the proposal wasnt finalized before WWDC, they chose one of them to introduce this feature to the world.

So its very likely that @propertyDelegate will be removed, and likely that @propertyWrapper will stay, although this could still change during the ongoing evolution process.

Synthesised init for a struct with @propertyWrapper members

As documented in:

  • Swift evolution proposals
  • Deep in the language guide

... you can get the compiler to do this for you, as it does with @State - just add a specific magic init(wrappedValue:) to your property wrapper definition:

@propertyWrapper
struct Prop<Value> {
var value: Value
var wrappedValue: Value {
get { value }
set { value = newValue }
}

// magic sauce
init(wrappedValue: Value) {
self.value = wrappedValue
}
}

struct B {
@Prop var s: String
}

let b = B(s: "string") // Now works

Incidentally, this also allows you to assign default values for your wrapped properties in the struct definition:

struct B {
@Prop var s: String = "default value" // Works now; would have thrown a compiler error before
}

What does the SwiftUI `@State` keyword do?

The @State keyword is a @propertyWrapper, a feature just recently introduced in Swift 5.1. As explained in the corresponding proposal, it's sort of a value wrapper avoiding boilerplate code.


Sidenote: @propertyWrapper has previously been called @propertyDelegate, but that has changed since. See this post for more information.


The official @State documentation has the following to say:

SwiftUI manages the storage of any property you declare as a state.
When the state value changes, the view invalidates its appearance and
recomputes the body
. Use the state as the single source of truth for a
given view.

A State instance isn’t the value itself; it’s a means of
reading and mutating the value
. To access a state’s underlying value,
use its value property.

So when you initialize a property that's marked @State, you're not actually creating your own variable, but rather prompting SwiftUI to create "something" in the background that stores what you set and monitors it from now on! Your @State var just acts as a delegate to access this wrapper.

Every time your @State variable is written, SwiftUI will know as it is monitoring it. It will also know whether the @State variable was read from the View's body. Using this information, it will be able to recompute any View having referenced a @State variable in its body after a change to this variable.

Can a Swift Property Wrapper reference the owner of the property its wrapping?

The answer is no, it's not possible with the current specification.

I wanted to do something similar. The best I could come up with was to use reflection in a function at the end of init(...). At least this way you can annotate your types and only add a single function call in init().


fileprivate protocol BindableObjectPropertySettable {
var didSet: () -> Void { get set }
}

@propertyDelegate
class BindableObjectProperty<T>: BindableObjectPropertySettable {
var value: T {
didSet {
self.didSet()
}
}
var didSet: () -> Void = { }
init(initialValue: T) {
self.value = initialValue
}
}

extension BindableObject {
// Call this at the end of init() after calling super
func bindProperties(_ didSet: @escaping () -> Void) {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if var child = child.value as? BindableObjectPropertySettable {
child.didSet = didSet
}
}
}
}


Related Topics



Leave a reply



Submit