-
-
Save MarqueIV/33d0636efa95477351b02af58632ba60 to your computer and use it in GitHub Desktop.
PropertyWrapper: @transaction binding for SwiftUI to make changes to data supporting commit/rollback
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct User: Equatable { | |
var firstName: String | |
var lastName: String | |
} | |
@main | |
struct MyApp: App { | |
@State var value = User(firstName: "", lastName: "") | |
@State var showEdit = false | |
var body: some Scene { | |
WindowGroup { | |
VStack { | |
Text("First Name: \(value.firstName)") | |
Text("Last Name: \(value.lastName)") | |
Button("Edit") { showEdit = true } | |
} | |
.sheet(isPresented: $showEdit) { | |
UserEditView(value: $value.transaction()) | |
} | |
} | |
} | |
} | |
struct UserEditView: View { | |
@Transaction var value: User | |
var body: some View { | |
VStack { | |
TextField("First Name", text: $value.firstName) | |
TextField("Last Name", text: $value.lastName) | |
Divider() | |
Button("Commit", action: $value.commit).disabled(!$value.hasChanges) | |
Button("Rollback", action: $value.rollback).disabled(!$value.hasChanges) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@main | |
struct MyApp: App { | |
@State var value = 0 | |
var body: some Scene { | |
WindowGroup { | |
MyView(value: $value.transaction()) | |
} | |
} | |
} | |
struct MyView: View { | |
@Transaction var value: Int | |
var body: some View { | |
VStack { | |
Text("Value: \(value)") | |
Text("HasChanges: \($value.hasChanges ? "yes" : "no")") | |
Divider() | |
Button("Increase") { value += 1 } | |
Button("Commit", action: $value.commit) | |
Button("Rollback", action: $value.rollback) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import Combine | |
@propertyWrapper | |
@dynamicMemberLookup | |
public struct Transaction<Value>: DynamicProperty { | |
@State private var derived: Value | |
@Binding private var source: Value | |
fileprivate init(source: Binding<Value>) { | |
self._source = source | |
self._derived = State(wrappedValue: source.wrappedValue) | |
} | |
public var wrappedValue: Value { | |
get { derived } | |
nonmutating set { derived = newValue } | |
} | |
public var projectedValue: Transaction<Value> { self } | |
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Value, T>) -> Binding<T> { | |
return $derived[dynamicMember: keyPath] | |
} | |
public var binding: Binding<Value> { $derived } | |
public func commit() { | |
source = derived | |
} | |
public func rollback() { | |
derived = source | |
} | |
} | |
extension Transaction where Value: Equatable { | |
public var hasChanges: Bool { return source != derived } | |
} | |
extension Binding { | |
public func transaction() -> Transaction<Value> { .init(source: self) } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment