Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Published property wrapper and its wrappedValue

Tags:

ios

swift

swiftui

When you define your own property wrapper you must specify a non-static property named 'wrappedValue'. For example:

@propertyWrapper
struct MyPropertyWrapper<Value> {
    var value: Value
}

with the code above the compiler complains that:

Property wrapper type 'MyPropertyWrapper' does not contain a non-static property named 'wrappedValue'

So, you can fix the error simply doing:

@propertyWrapper
struct MyPropertyWrapper<Value> {
    var value: Value

    var wrappedValue: Value {
        get {
            value
        }
        set {
            value = newValue
        }
    }
}

Just to make some examples this is true for @State:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct State<Value> : DynamicProperty {

    /// The current state value.
    public var wrappedValue: Value { get nonmutating set }
}

the same for @Binding:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper @dynamicMemberLookup public struct Binding<Value> {

    /// The value referenced by the binding. Assignments to the value
    /// will be immediately visible on reading (assuming the binding
    /// represents a mutable location), but the view changes they cause
    /// may be processed asynchronously to the assignment.
    public var wrappedValue: Value { get nonmutating set }
}

and so forth. But the @Published property wrapper doesn't have a wrapped value:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct Published<Value> {

    /// Initialize the storage of the Published property as well as the corresponding `Publisher`.
    public init(initialValue: Value)

    /// A publisher for properties marked with the `@Published` attribute.
    public struct Publisher : Publisher {

        /// The kind of values published by this publisher.
        public typealias Output = Value

        /// The kind of errors this publisher might publish.
        ///
        /// Use `Never` if this `Publisher` does not publish errors.
        public typealias Failure = Never

        /// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)`
        ///
        /// - SeeAlso: `subscribe(_:)`
        /// - Parameters:
        ///     - subscriber: The subscriber to attach to this `Publisher`.
        ///                   once attached it can begin to receive values.
        public func receive<S>(subscriber: S) where Value == S.Input, S : Subscriber, S.Failure == Published<Value>.Publisher.Failure
    }

    /// The property that can be accessed with the `$` syntax and allows access to the `Publisher`
    public var projectedValue: Published<Value>.Publisher { mutating get }
}

I'm missing something for sure here, since the compiler won't let you create a property wrapper without the wrappedValue. What's the difference in this case respect to the other property wrappers?

like image 435
matteopuc Avatar asked Oct 10 '19 19:10

matteopuc


People also ask

What is @published property wrapper?

@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.

What is a property wrapper?

A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property. For example, if you have properties that provide thread-safety checks or store their underlying data in a database, you have to write that code on every property.

What is Wrappedvalue in Swift?

A projection of the binding value that returns a binding. Returns a binding to the resulting value of a given key path.

What is EnvironmentObject?

What is an @EnvironmentObject? An @EnvironmentObject is an object living in the current environment, available to read whenever needed. An environment object is defined at a higher-level view, and can any child view can access it if needed.


1 Answers

The code you have shown isn't the actual implementation of @Published - It is merely the publicly visible interface. If you paste that code into Xcode you will get the same error regarding wrappedValue among others; That code doesn't compile.

wrappedValue has an access level of internal - So we can assume that the actual implementation of @Published declares something like internal var wrappedValue:Value. This satisfies the property wrapper requirement but means that wrappedValue is not visible outside of its framework.

like image 59
Paulw11 Avatar answered Oct 16 '22 10:10

Paulw11