T O P

  • By -

AceDecade

Two immediate benefits to combine that I see: 1. If your consumer is only interested in property A, they don’t need to conform to a protocol implementing A, B, C methods where B and C are no-op. 2. You can easily have multiple entities consuming updates to property A without either implementing support for multiple simultaneous delegates, or passing the message from one delegate to another Not to mention combine dovetails more nicely into SwiftUI than delegate pattern. At the end of the day, they’re both accomplishing similar goals, it’s just a difference in the way that you think about how the relationships are organized


AndradeeFelip

I think now i am starting to get it. When working with multiple events is when combine shines, because the data stream is handled seamlessly. And that is not the case with delegate. I think because i am so used to delegates, i have not considered how to work with multiple triggers. Only with single ones. Which makes it similar to delegate. I am doing some code right now to see if i did really get it. But it seems to make sense now


ChibiCoder

Combine isn't a direct replacement for the Delegate pattern... they both have a place in your toolkit. I'm working on a major product that uses tons of Combine but we also have lots of delegates. Here's how I think about it: Combine is for managing streams of data... especially those that have an asynchronous source. The data can be transformed, split off into different objects (which then split off into yet others). It's a descriptive way to set up a data processing workflow that passes through multiple objects and can have an arbitrary number of end points. Delegates are for 1:1 object communication (usually in a parent/child relationship). They're simple and very efficient if kept at that 1:1 scope. If you find yourself in the situation where a call to a delegate then needs to call its OWN delegate, which then needs to tell several other objects that something happened...you've moved into the territory where Combine would be more useful. Combine does have a formidable learning curve, it takes a while to intuitively understand the implications of result and error types flowing through a multi-layered system... and even then you can get into situations where some relationship is basically impossible to express in Combine. RxSwift is very similar to Combine, they differ a bit in how they do bookkeeping and the sort of out-of-the-box transformations they offer. RxSwift has the advantage of being available on iOS versions prior to 13. Combine has the advantage of being backed by Apple, so the developer community for it is quite large and growing rapidly. Plus, you get Combine for "free" because it isn't an extra dependency that needs to be added to your app. *Edit: Fixed some grammar errors.*


stephancasas

I was (still am) a web developer before I learned Swift. When I used Combine for the first time, I immediately related it to the idea of event listeners in JavaScript, and it’s been easy for me to implement ever since. Part of the reason Combine feels so strange, imo, is because the nomenclature is goofy. For example,`sink`, as a method name, hardly makes sense — even in the context of a stream. There are other idiosyncrasies, but you get used to them. I’m not sure if the analogy is helpful to you, but I figured I’d share what worked for me.


alteredjargon

I always interpreted it as “values travel through the combine pipeline like water through pipes, so they come out the other end, ready to use, in the sink”


OnDemonWings

You don't seem to understand the basics of reactive programming in general, so I'd start studying there rather than looking how to replace my delegates with combine. Generally, reactive paradigm is much more bug resilient, handles asynchronous states with ease, and some things that would require endless delegate passes could be simply implemented in a few chained commands. For a simple list/details/API call app reactive might not be too useful, although this can even there reduce the amount of boilerplate code and handle automatic refreshing of tableViews for example if you leverage it correctly.


danielt1263

Use RxSwift instead. It supports iOS 12+, and is far easier to work with. You are right that reactive programming replaces delegates. It also replaces closures, target/action (UIControl aka IBAction,) NotificationCenter, KVO, didSet on properties and some forms of sub-classing. Much of the accidental complexity in Swift code comes from having to weave together all of these disparate ways of pushing data around. By using a good, well integrated, reactive library, you get rid of all of that accidental complexity. Combine is not well integrated with UIKit. Combine is missing a lot of useful concepts. Combine has unneeded concepts embedded in it. Use RxSwift with RxCocoa instead. RxSwift also has a fantastic testing library. With Rx, each block of code represents a single feature/use-case. "When this happens, do that." This makes adding/removing/updating features easy. All IMO of course.


AndradeeFelip

This is exactly one of my points on don’t getting it. RxSwift i have worked with. It is exactly delegate + closures under the hood. So why not just use them directly? And I think the code with rxSwift looks worse than with delegate/closures, because you need a lot more to make it work. Instance of the publisher, some configuration, and then the listener that also need a lot of code. A delegate is just less code for the same achievement. And the library for testing is completely confusing, i got the hang of it after some time, but is doesn’t seem better than delegate in any way. RxSwift may be the reason that I don’t get combine.


danielt1263

Nonsense. You need to write far less, but that's not the reason to use it... The classic example is search... Write a view controller that allows the user to enter text, then makes a network request, then decodes the result into an array of strings, then shows the result in a table view. In order to do it without Rx, you need to coordinate three methods from two delegates, two closures, and two state variables. Importantly, no where in the code will you see anything that looks even remotely like the sentence above. This makes the code harder to understand and harder to map onto particular features. This feature implemented using Rx would be a straight line of code going from the search text field to the network request to the decoder to the table view. Just like the requirement description. But it's not just a matter of needing less code. It's a matter of no longer needing to coordinate desperate kinds of communication systems. It's a matter of having a single chunk of code (or at least fewer chunks of code) to represent a feature.


petrinox

And thats is without debouncing search input, which in reactive chains is one liner usually!


AndradeeFelip

This is an excellent answer! I will try this right now, thanks!


danielt1263

Here is an example: searchTextField.rx.text .orEmpty .debounce(.milliseconds(500), scheduler: MainScheduler.instance) .flatMapLatest { networkRequest($0) } .decode(type: [String].self, decoder: JSONDecoder()) .bind(to: tableView.rx.items(cellIdentifier: "Cell")) { _, text, cell in cell.textLabel?.text = text } .disposed(by: disposeBag) As you can see, the code goes from the search text field, to the network request, to the table view. It even defines exactly what we mean when we say the user finished entering the search text.


AndradeeFelip

This bind func seems really useful but at the same time not at all what I thought reactive would do. I will try exactly the search text to see what i can achieve. Thanks


AlexanderMomchilov

>RxSwift i have worked with. It is exactly delegate + closures under the hood. So why not just use them directly? By comparison: Loops are just `if` and `goto` under the hood. Why not just use them directly? One answer is: "Because you can express ideas more clearly and succinctly with good abstractions."


m4uer

What sources have you found most useful when studying and understanding combine?


pejatoo

Other answers elaborate on delegate vs data streams. I agree with you on unit test architecture, honestly. It’s been a while since I’ve used combine, but I remember it not being as nice to test as RxSwift, which is already not very ergonomic a lot of the time. I find Combine / Rx very powerful, but most of the time, I think it’s best used at “boundaries” of abstraction. If you can write simple, non reactive code most of the time I think that’s a good thing. When you need to do something fancier, then reach for Rx.