Last active
September 13, 2024 10:32
-
-
Save PaulWoodIII/781c26ff1a85ed6f074c994ccb065cef to your computer and use it in GitHub Desktop.
Bindings over a CurrentValue subject allow you to use combine for side affects
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
//: [Previous](@previous) | |
import Foundation | |
import SwiftUI | |
import Combine | |
//: Current Value Subject is a value, a publisher and a subscriber all in one | |
let currentValueSubject = CurrentValueSubject<Bool, Never>(true) | |
print(currentValueSubject.value) | |
//: Bindings are used in SwiftUI to get and Set state, CurrentValueSubjects work well with Bindings | |
let binding = Binding<Bool>( | |
get:{ | |
return currentValueSubject.value | |
}, | |
set:{ | |
currentValueSubject.send($0) | |
}) | |
print("The Binding is NOT the value \(binding)\n see how it is an object not just Bool") | |
//: INstead to get the current value use `wrappedValue` | |
print("The Value is now \(binding.wrappedValue)") | |
//: Now Lets Set the binding to false to see how it affects the currentValueSubject | |
binding.wrappedValue = false | |
print("The Value is now \(binding.wrappedValue)") | |
//: The currentValueSubject can also send(_:) affecting the value displayed by the binding | |
currentValueSubject.send(true) | |
print("The Value is now \(binding.wrappedValue)") | |
//: Lets do something random and display the set | |
//: First lets create a stream that listens to the values of our currentValueSubject, lets maps the booleans to a string just for show | |
var allStrings: [String]? | |
let cancel = currentValueSubject.map({ (next) -> String in | |
if next { | |
return "Set To True" | |
} else { | |
return "Set To False" | |
} | |
}) | |
//: Collect will hold all the values in an array until .finished is sent | |
.collect().sink { (collectedStrings) in | |
// Sink will set our array with the array collected when the currentValueSubject has finished | |
allStrings = collectedStrings | |
} | |
//: Here we Set the binding 10 random times, run the playground more than once to check | |
for _ in 0..<10 { | |
let randomBool = arc4random() % 2 == 0 // flip a coin ;) | |
binding.wrappedValue = randomBool | |
} | |
//: Complete the stream, in a real app this might be from deallocation of an object that owns it for example | |
currentValueSubject.send(completion: .finished) | |
//: when you subscribe to the currentValue Subject it will send the latest value to the subscriber how many items do you expect in allStrings? | |
print("Number of items collected: \(allStrings!.count)") | |
//: Lets print all of the items out | |
print(allStrings!.joined(separator: ",\n")) | |
//: [Next](@next) |
Thank you, this is fantastic. That said, I still wonder why there isn't a simpler way, built in SwiftUI.
extension CurrentValueSubject {
var binding: Binding<Output> {
Binding(get: {
self.value
}, set: {
self.send($0)
})
}
}
mySubject.binding
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great learning thanks!