I recently worked on SwiftUI and starting writing code in a declarative way. But here comes a confusion. Like what is shown below, I want to (1)load the song data and (2)show the view by setting isInfoViewShown
, after song
is assigned to any value.
I assume didSet{}
and Combine @Published .sink{}
are doing things interchangeably. So I want to ask what are the differences between them? And in my own opinion, didSet{}
can do most of jobs Combine
do. So why should Apple announce Combine
framework?
Any help is appreciated.
class InfoViewModel: ObservableObject {
@Published var song: Song? {
didSet { // Here's the didSet{}: [1] load song data
if let song = song {
load(song: song)
}
}
}
private var songSelectedSubscription: AnyCancellable?
@Published var isInfoViewShown: Bool = false
init() { // Here's the Combine @Published .sink{}: [2] show the view
songSelectedSubscription = $song.sink{ self.isInfoViewShown = ($0 == nil ? false : true) }
}
}
Sure, there are lots of ways to observe changes to data, KVO, Notification Center, didSet, combine etc, so in one sense these things are indeed similar. Differences though are:
a property can only have one didSet, which makes it hard for any number of observers to register an interest in the property.
But the big win with Combine is: a Combine pipeline allows you to create streams easily where you can say for example, transform the stream of changes to a stream that: observes changes to the user's input string, debounces it (rate limiting changes so we don't spam the server), filter those changes for any value that is at least 3 characters long, and that produces a new stream which you can observe. Map/FlatMap is also a really important combine operator, transform a stream of a's into a stream of b's. Also merging two streams together with combineLatest and so on, so you can take a stream of a's and stream of b's and make a stream of (a, b)'s and then map that to a stream of validated c's, for example.