Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Created July 17, 2020 00:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IanKeen/84ca0b22be73f6ebe97269108d4a789b to your computer and use it in GitHub Desktop.
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
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() { }
}
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