Created
July 17, 2020 00:51
-
-
Save IanKeen/84ca0b22be73f6ebe97269108d4a789b to your computer and use it in GitHub Desktop.
PropertyWrapper: @input provides a write-only interface externally, but a subject available internally for modelling reactive streams in Combine
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 Combine | |
@propertyWrapper | |
public struct Input<T> { | |
public struct SendProxy { | |
private let send: (T) -> Void | |
fileprivate init(_ send: @escaping (T) -> Void) { | |
self.send = send | |
} | |
public func callAsFunction(_ value: T) { | |
send(value) | |
} | |
} | |
public let subject = PassthroughSubject<T, Never>() | |
public var wrappedValue: T { | |
get { fatalError("Inputs are write only") } | |
set { fatalError("Inputs should only be written to via the $projectedValue") } | |
} | |
public var projectedValue: SendProxy { .init(subject.send) } | |
public init() { } | |
} |
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
class MyViewModel: ObservableObject { | |
// MARK: - Inputs | |
@Input var add: Int | |
// MARK: - Outputs | |
@Published var count: Int = 0 | |
// MARK: - Lifecycle | |
init() { | |
_add.subject | |
.combineLatest($count, +) | |
.assign(to: $count) | |
} | |
} | |
struct MyView: View { | |
@StateObject var viewModel = MyViewModel() | |
var body: some View { | |
VStack { | |
Text("\(viewModel.count)") | |
Button("Add", action: { viewModel.$add(1) }) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment