Skip to content

Instantly share code, notes, and snippets.

@n8chur
Last active March 2, 2022 06:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save n8chur/e1e055b91c626014d917d3d7f7a0ad61 to your computer and use it in GitHub Desktop.
Save n8chur/e1e055b91c626014d917d3d7f7a0ad61 to your computer and use it in GitHub Desktop.
An example implementation of @published from Swift's Combine framework along with an "immutable" variant.
import Combine
/**
An observable, mutable property.
Replays the current value when subscribed.
*/
@propertyWrapper
struct Published<Output>: Publisher {
typealias Failure = Never
private let subject: CurrentValueSubject<Output, Never>
var value: Output {
get { subject.value }
nonmutating set { subject.value = newValue }
}
init(initialValue: Output) {
subject = CurrentValueSubject<Output, Never>(initialValue)
}
func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
subject.receive(subscriber: subscriber)
}
}
/**
An immutable, observable property.
Replays the current value when subscribed.
*/
@propertyWrapper
struct ImmutablePublished<Output>: Publisher {
typealias Failure = Never
private let subject: CurrentValueSubject<Output, Failure>
var value: Output { subject.value }
private let cancellable: Cancellable
init(_ publisher: AnyPublisher<Output, Failure>, initialValue: Output) {
subject = CurrentValueSubject<Output, Failure>(initialValue)
cancellable = publisher.assign(to: \.value, on: subject)
}
func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
subject.receive(subscriber: subscriber)
}
}
@n8chur
Copy link
Author

n8chur commented Jun 10, 2019

I'm having a hard time coming up with a valid use case for ImmutablePublished. In all the scenarios I've imagined you'd likely be better off with a @Published private(set) var ....

@n8chur
Copy link
Author

n8chur commented Jun 10, 2019

I thought of one benefit of @ImmutablePublished var ... over @Published private(set) var ... — with @ImmutablePublished you cannot access the underlying property wrapper to change the value.

Consider the following:

struct Foo {
    @Published
    private(set) var bar = "Bar"
}

let foo = Foo()
// This isn't valid and will not compile
foo.bar = "Qux"
// but this works:
$foo.value = "Qux

Using @ImmutablePublished would prevent access to the underlying property wrapper's setter.

@dshikulin-mwb
Copy link

It misses projectedValue and I guess it won't trigger objectWillChange of ObservableObject

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment