@Published 属性包装器及其wrappedValue

sup*_*cio 11 ios swift swiftui

当您定义自己的属性包装器时,您必须指定一个名为 'wrappedValue'非静态属性。例如:

@propertyWrapper
struct MyPropertyWrapper<Value> {
    var value: Value
}
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,编译器抱怨:

属性包装器类型“MyPropertyWrapper”不包含名为“wrappedValue”的非静态属性

因此,您只需执行以下操作即可修复错误:

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

    var wrappedValue: Value {
        get {
            value
        }
        set {
            value = newValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

只是举一些例子,这适用于@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 }
}
Run Code Online (Sandbox Code Playgroud)

相同的@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 }
}
Run Code Online (Sandbox Code Playgroud)

等等。但是@Published属性包装器没有包装值:

@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 }
}
Run Code Online (Sandbox Code Playgroud)

我在这里肯定遗漏了一些东西,因为编译器不会让你在没有wrappedValue. 在这种情况下,与其他属性包装器有什么区别?

Pau*_*w11 10

你已经显示的代码是不实际执行@Published-它仅仅是公开可见的接口。如果您将该代码粘贴到 Xcode 中,您将收到与wrappedValue其他代码相同的错误;该代码无法编译。

wrappedValue访问级别为internal- 所以我们可以假设实际的实现@Published声明了类似internal var wrappedValue:Value. 这满足属性包装器要求,但意味着它wrappedValue在其框架之外不可见。

  • 我尝试为我的“公共”属性包装器添加一个“内部”wrappedValue,但编译器仍然不允许编译代码。错误如下:“内部属性‘wrappedValue’不能比其封闭属性包装类型‘SomeWrapper’(公共)具有更多限制性访问” (2认同)