Skip to content

Instantly share code, notes, and snippets.

@alexdremov
Created October 22, 2022 10:21
Show Gist options
  • Save alexdremov/a4ffdddb714480bc31ad4f436ff34183 to your computer and use it in GitHub Desktop.
Save alexdremov/a4ffdddb714480bc31ad4f436ff34183 to your computer and use it in GitHub Desktop.
class LogInState: ObservableObject {
@Published var isLoggedIn: Bool
init(isLoggedIn: Bool) {
self.isLoggedIn = isLoggedIn
}
func loggedOut() {
isLoggedIn = false
}
func loggedIn() {
isLoggedIn = true
}
}
struct MyView: View {
@ObservedObject var logInState: LogInState
var body: some View {
Text(logInState.isLoggedIn ? "Yes" : "No")
}
}
...
let logInState = LogInState(isLoggedIn: true)
HomePageModule(logInState: logInState)
...
SettingsModule(logInState: logInState)
struct ReadOnlyModule: View {
@ObservedObject
@ObservableValue
var logInState: Bool
init(logInState: ObservableValue<Bool>) {
self._logInState = .init(wrappedValue: logInState)
}
var body: some View {
Text(logInState ? "Yes" : "No")
}
}
struct ModifyModule: View {
@ObservableProperty
var logInState: Bool
init(logInState: ObservableProperty<Bool>) {
self._logInState = logInState
}
var body: some View {
Button("toggle") {
logInState = !logInState
}
}
}
struct MyView: View {
@ObservableProperty
var logInState: Bool
init(logInState: ObservableProperty<Bool>) {
self._logInState = logInState
}
var body: some View {
VStack {
// projected read-only value (ObservableValue)
ReadOnlyModule(logInState: $logInState)
// ObservableProperty reference
ModifyModule(logInState: _logInState)
}
}
}
struct MyView: View {
@ObservedObject
@ObservableProperty
var logInState: Bool
init(logInState: ObservableProperty<Bool>) {
self._logInState = .init(initialValue: logInState)
}
var body: some View {
VStack {
Text(logInState ? "Yes" : "No")
Button("toggle") {
logInState = !logInState
}
}
}
}
@dynamicMemberLookup
@propertyWrapper
public class ObservableProperty<Output>: ObservableObject {
@Published private var storedValue: Output
public var wrappedValue: Output {
get {
storedValue
}
set {
storedValue = newValue
}
}
public init(wrappedValue initialValue: Output) {
self.storedValue = initialValue
}
public subscript<Result>(dynamicMember keyPath: WritableKeyPath<Output, Result>) -> Result {
get {
storedValue[keyPath: keyPath]
}
set {
storedValue[keyPath: keyPath] = newValue
}
}
public subscript<Result>(dynamicMember keyPath: KeyPath<Output, Result>) -> Result {
storedValue[keyPath: keyPath]
}
public var publisher: AnyPublisher<Output, Never> {
$storedValue.eraseToAnyPublisher()
}
public var projectedValue: ObservableValue<Output> {
ObservableValue<Output>(
initialValue: storedValue,
publisher: publisher
)
}
}
public class ObservableProperty<Output>: ObservableObject {
...
public var publisher: AnyPublisher<Output, Never> {
$storedValue.eraseToAnyPublisher()
}
public var projectedValue: ObservableValue<Output> {
ObservableValue<Output>(
initialValue: storedValue,
publisher: publisher
)
}
...
}
import Foundation
import Combine
@dynamicMemberLookup
@propertyWrapper
public class ObservableProperty<Output>: ObservableObject {
@Published private var storedValue: Output
public var wrappedValue: Output {
get {
storedValue
}
set {
storedValue = newValue
}
}
public init(wrappedValue initialValue: Output) {
self.storedValue = initialValue
}
public subscript<Result>(dynamicMember keyPath: WritableKeyPath<Output, Result>) -> Result {
get {
storedValue[keyPath: keyPath]
}
set {
storedValue[keyPath: keyPath] = newValue
}
}
public subscript<Result>(dynamicMember keyPath: KeyPath<Output, Result>) -> Result {
storedValue[keyPath: keyPath]
}
}
@dynamicMemberLookup
@propertyWrapper
public class ObservableValue<Output>: ObservableObject {
@Published private var storedValue: Output
private var cancellable: AnyCancellable?
public var wrappedValue: Output {
storedValue
}
public init(wrappedValue initialValue: Output) {
fatalError("ObservableValue cannot be initialized with value. Use constant()")
}
init<Pub: Publisher<Output, Never>>(initialValue: Output, publisher: Pub) {
storedValue = initialValue
cancellable = publisher.sink { newValue in
self.storedValue = newValue
}
}
public subscript<Result>(dynamicMember keyPath: WritableKeyPath<Output, Result>) -> Result {
get {
storedValue[keyPath: keyPath]
}
set {
storedValue[keyPath: keyPath] = newValue
}
}
public subscript<Result>(dynamicMember keyPath: KeyPath<Output, Result>) -> Result {
storedValue[keyPath: keyPath]
}
public static func constant(initialValue: Output) -> ObservableValue<Output> {
.init(
initialValue: initialValue,
publisher: Empty()
)
}
public var publisher: Published<Output>.Publisher {
$storedValue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment