Publisher
Create
By utilizing property wrapper we can just decorate any variable with @Pubished
to make it publish-eable
@Published var someVariable: String = ""
UserDefault custom property wrapper example codable
Note:
Well suited for SwiftUI + Combine.
willSet
internally it calls so that SwiftUI can make optimizations towards what should be refreshed on the UI when compared directly to CurrentValueSubject
subjects
Create custom Publisher
building-custom-combine-publishers-in-swift
lets-build-a-custom-publisher-in-combine
Migrating to @Observable
View Model
import Combine
final class AppSettings: ObservableObject {
@Published var confirmDeletion = true
}
// VS
import Observation
@Observable final class AppSettings {
var confirmDeletion = true
}
View
struct SettingsView: View {
@ObservedObject var appSettings: AppSettings
}
// VS
struct SettingsView: View {
var appSettings: AppSettings
}
Type Erasure
Just for reference if anyone is reading this one of the fundamental concepts of combine/reactive paradigm when everything is a stream / observable sequence.
private let eventSubject = PassthroughSubject<EngineEvent, Never>()
When an observable is being initialized (it can be hot / cold) without going to overboard - here because its an PassThroughSubject
which doesn't require initial value equivalent PublishSubject
of RxSwift.
let eventPublisher: AnyPublisher<EngineEvent, Never>
init() {
eventPublisher = eventSubject.eraseToAnyPublisher()
}
extension EngineEventBus: EventSendable {
func sendEvent(_ type: EventType, metaData: EventMetaData?, url: URL) {
eventSubject.send(EngineEvent(type: type, metaData: metaData, url: url))
}
}
But author also has an extension with function to add explicit setters via a protocol EventSendable
It does contradict sometimes with the purely functional reactive paradigm but this gives us more flexibility in the long run while doing more checks for sending
values upstream.
Apple doc reference doesn't make it crystal clear but if its any consolation - Reactive programming is harder to grasp at first level.
PS: Sorry for the long winded comment but I had a tough time wrapping my head around with Reactive programming when I was starting out. So adding this comment for others who are reviewing if that makes even 5% sense is helpful.
Did Set
When you want to debug the Published properties, you can use didSet
to get some more insights about the lifecycle of these combine properties.
@Published private var audioTracks: [AudioTrack] = [] {
didSet {
print("didSet \(audioTracks)")
}
}
Errors
Cannot convert value of type 'Published<>.Publisher' to expected argument type 'Binding<>'
copied from slack overflow
Not sure why the proposed solutions here are so complex, when there is a very direct fix for this.
Found this answer on a similar Reddit question:
The problem is that you are accessing the projected value of an @Published (which is a Publisher) when you should instead be accessing the projected value of an @ObservedObject (which is a Binding), that is: you have
globalSettings.$tutorialView
where you should have$globalSettings.tutorialView
.
Reference
Great article about how reactive paradigm works in a way. Touches how we can support pre iOS 13 deployment targets and make use of custom property wrappers to have a temporary migration solution for older devices. Or we can use community adopted RxSwift reactive framework to work with it. Either way this article sheds a light on approaching a problem with 3 different ways which I always prefer when making those architectural decisions.
Connecting and merging Combine publishers in Swift
how-to-clean-up-resources-when-a-combine-publisher-is-cancelled