Skip to content

Instantly share code, notes, and snippets.

@PaulWoodIII
Last active January 9, 2024 01:20
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save PaulWoodIII/781c26ff1a85ed6f074c994ccb065cef to your computer and use it in GitHub Desktop.
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
//: [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)
@arashkashi
Copy link

Great learning thanks!

@jordymeow
Copy link

Thank you, this is fantastic. That said, I still wonder why there isn't a simpler way, built in SwiftUI.

@jpmcglone
Copy link

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