Skip to content

Instantly share code, notes, and snippets.

@Alex009
Created February 28, 2025 05:29
Show Gist options
  • Save Alex009/58adda1ebe235525a6d4275757bcefd8 to your computer and use it in GitHub Desktop.
Save Alex009/58adda1ebe235525a6d4275757bcefd8 to your computer and use it in GitHub Desktop.
SwiftUI Binding for MutableStateFlow
// code from Chris Hatton - https://kotlinlang.slack.com/archives/C9JM6Q2UX/p1740462546873469?thread_ts=1740462525.562349&cid=C9JM6Q2UX
struct FlowBinding<FlowValue: Equatable, BoundValue: Equatable, Content>: View where Content: View {
private let mutableStateFlow: SkieSwiftMutableStateFlow<FlowValue>
private let content: (Binding<BoundValue>) -> Content
private let transformOut: (FlowValue) -> BoundValue
private let transformIn: (BoundValue) -> FlowValue
// Track the source of truth internally
@State private var currentValue: BoundValue
@State private var lastFlowValue: FlowValue
init(
mutableStateFlow: SkieSwiftMutableStateFlow<FlowValue>,
transformOut: @escaping (FlowValue) -> BoundValue,
transformIn: @escaping (BoundValue) -> FlowValue,
@SwiftUI.ViewBuilder content: @escaping (Binding<BoundValue>) -> Content
) {
self.mutableStateFlow = mutableStateFlow
self.content = content
self.transformIn = transformIn
self.transformOut = transformOut
let initialFlowValue = mutableStateFlow.value
self._lastFlowValue = State(initialValue: initialFlowValue)
self._currentValue = State(initialValue: transformOut(initialFlowValue))
}
var body: some View {
let binding = Binding<BoundValue>(
get: { currentValue },
set: { newValue in
// Update our local value first
currentValue = newValue
// Calculate and set the new flow value
let newFlowValue = transformIn(newValue)
// Break update cycle early (even if StateFlow would do this)
if newFlowValue != lastFlowValue {
lastFlowValue = newFlowValue
mutableStateFlow.value = newFlowValue
}
}
)
return content(binding)
.collect(flow: mutableStateFlow) { newFlowValue in
lastFlowValue = newFlowValue
currentValue = transformOut(newFlowValue)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment