Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic trigger for objectWillChange publisher #6

Merged

Conversation

jlsiewert
Copy link
Contributor

@jlsiewert jlsiewert commented Sep 30, 2022

Automatically triggers the objectWillChange publisher in Combines ObservableObject.

Heavily inspired by John Sundell and the @propertyWrapper Swift Evolution Proposal.

fixes #5

@jlsiewert
Copy link
Contributor Author

By adding the public subscript

public static subscript<T: ObservableObject>(
         _enclosingInstance instance: T,
         wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Value>,
         storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
     ) -> Value where T.ObjectWillChangePublisher == ObservableObjectPublisher

we are in fact enforcing that the property wrapper can only be used within an ObservableObject with the default ObservableObjectPublisher, what is probably not what we want.

The best solution would probably be to provide two implementation, one more specialised then the other, like so:

public static subscript<T: AnyObject>(
        _enclosingInstance instance: T,
        wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Value>,
        storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
    ) -> Value {
        get {
            // Return the saved wrapped value
            instance[keyPath: storageKeyPath].wrappedValue
        }
        set {
            instance[keyPath: storageKeyPath].wrappedValue = newValue
        }
    }

    public static subscript<T: ObservableObject>(
        _enclosingInstance instance: T,
        wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Value>,
        storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
    ) -> Value where T.ObjectWillChangePublisher == ObservableObjectPublisher {
        get {
            // Return the saved wrapped value
            instance[keyPath: storageKeyPath].wrappedValue
        }
        set {
            instance.objectWillChange.send()
            instance[keyPath: storageKeyPath].wrappedValue = newValue
        }
    }

However, that currently produces the error Property wrapper type 'AsyncValue' has multiple enclosing-self subscripts 'subscript(_enclosingInstance:wrapped:storage:)', as described as in apple/swift#54777

For now, we could fall back for a runtime check:

public static subscript<T: AnyObject>(
        _enclosingInstance instance: T,
        wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Value>,
        storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
    ) -> Value {
        get {
            // Return the saved wrapped value
            instance[keyPath: storageKeyPath].wrappedValue
        }
        set {
            if let instance = instance as? any ObservableObject,
               let publisher = (instance.objectWillChange as any Publisher) as? ObservableObjectPublisher {
                // Trigger the `ObjectWillChangePublisher`
                publisher.send()
            }
            instance[keyPath: storageKeyPath].wrappedValue = newValue
        }
    }

@BrentMifsud
Copy link
Owner

Hey thanks for contributing! I was looking into adding something like this so users don't have to keep adding a willSet.

I'll take a closer look tomorrow when I have some time.

@BrentMifsud
Copy link
Owner

BrentMifsud commented Oct 2, 2022

Hey looks good.

Going to force merge this as there's a permission issue with the GitHub actions.

@BrentMifsud BrentMifsud merged commit dc258d0 into BrentMifsud:main Oct 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature] automatic trigger for objectWillChange publisher
2 participants