Here at Aspire, we pride ourselves in keeping up with the latest technologies, frameworks and releases, in order to share our best practices and experience with our clients. Our very own Senior iOS developer, Ahmad Fayyas wrote a great article on Medium about his first impressions of the Combine Framework. Check it out below:
A while ago, I published an article about my first impression for SwiftUI framework. In the article, I mentioned that SwiftUI could be more than a UI handler for our projects. After diving a bit deeper in SwiftUI (and Swift 5.1), I recognized that States and bindings are (obviously) really nice. By using some of the provided property wrappers such as @State, @Binding or @ObjectBinding, we are able to connect our views with our data models very easily and more expressively.
One of the new topics that I noticed, was that in order to declare a @ObjectBinding variable of your custom view model type, you have to let it conform to BindableObject protocol. After that, you can then implement didChange property, which is of type PassthroughSubject. If we trace the PassthroughSubject hierarchy, we’ll find out that it is a class, which is a concrete type of Subject protocol, that conforms to Publisher protocol – this all means that it is basically a Publisher. Okay, so what is this all about ?????
Are we getting far away from SwiftUI?
The answer is yes. When reviewing the Publisher documentation, if you have sharp eyes (not really, it’s clear enough ????), you’ll notice that it relates to the family of Combine framework:
This is not a tutorial of coding with Combine framework, it is just an iOS developer’s first impression about how we’ll deal with it.
Hello, Combine!
Apple simply describes Combine as:
‘Customize handling of asynchronous events by combining event-processing operators’.
Honestly, my very first impression when I started reading the used “technical terms” in the framework documentation such as Publisher , Just Subscriber , Subscription, Operators , Cancellable , Scheduler , my mind automatically connected them as keywords with the world of FRP!
So, YES, if you are familiar with one of the FRP frameworks such as RxSwift or ReactiveCocoa then congratulations! Now you know the main reason of the Combine framework existence. Currently, we can say that Apple does support the FRP paradigm natively without the need for dealing with a third-party framework for building our projects ????.
Finally, Apple!
But wait… What if I have no idea what FRP is?
Well… I would say it is a good opportunity to find out ????.
Basically, dealing with Functional Reactive Programming (FRP) let’s you worry less about managing data and allows you to concentrate on how your apps should work. Here are some of the points that describe the meaning of “worry less about managing data”:
- The parts of your app might be affected.
- The amount of the (“tedious” in some cases) boilerplate code that you might need to implement (Hello Delegates, Targets-Actions, KVOs …!).
- Caring about synchronous/asynchronous changes, and how to connect their impact to the default app’s data flows.
Additionally, it might be worth mentioning that when comparing FRP with the usual standard approach(es), most of the time you’ll need to write less code to achieve the same results; It’s about performing things “declaratively”.
Less code?!
To clarify, take a look at one of the most popular cases we might achieve in our apps, which is dealing with multiple asynchronous calls. Obviously, we should think about one of the concurrency techniques, one of the proper choices would be the GCD DispachGroup. Whether the tasks are on the same queue or on different queues, we are still able to observe the execution and completion of them in the group. Example:
<let queue = DispatchQueue(label: “reverseDomain”, attributes: .concurrent)
let group = DispatchGroup() queue.async (group: group) { performAsync01() } queue.async (group: group) { performAsync02() } queue.async (group: group) { performAsync03() } group.notify(queue: DispatchQueue.main) { // tasks executions are finished } |
Keep in mind that the output of the asynchronous task might be a returned value, therefore, in addition to the above code, we might need to declare an instance variable to set the returned value in order to access it.
So, what about Combine?
let myPublisher = Publishers.Zip3(photoSubject, stringSubject, voidSubject)
myPublisher.sink { (asset, string, _) in // tasks executions are finished // additionally, we can directly access the tasks (subjects) outputs } |
Note that photoSubject , stringSubject and voidSubject are predefined Subjects (which are basically Publishers). We just applied zipping for the upstream publishers by using Zip3, and that’s all! The beauty of it is not only about the amount of code that has been written, it’s also about the used paradigm for achieving such task.
Moreover, by the time you’ll work with publishers, you’ll find out that there are many useful operators to act on the received value(s) from publishers and republish them, its awesome!
What does it mean to me as a developer?
We can see that we’ll have a chance (and it might be the only required way in the future) to change the used approaches for developing our iOS apps by using these provided frameworks. Some of the developers are keen to learn it, some of them are getting bored of having to keep dealing with all this new stuff, and the rest are just like: “yeah whatever…”.
Although I won’t say that learning and working with Combine is a must (at least for now), whether we like it or not, you should keep in mind that it exists. Perhaps we’ll see in the near future a new generation of iOS developers who only know how to settle things with Combine and nothing else! Is it possible?!
Us, the old generation.
Furthermore, you might have heard of the theory of:
In order to apply an alternative architectural design pattern such as MVVM, I have to know the “reactive programming” thing.
It doesn’t have to be absolutely correct, but it makes sense! That’s because applying a pattern such as MVVM appropriately requires two-way data binding, which is painful without following the reactive programming approach to achieve it.
By the way, am I allowed to use Combine without using SwiftUI?
Yes, you are not limited to use Combine only with SwiftUI. You can use Combine framework with UIKit, which means that you are able to build the UI part of your application as you usually do meanwhile leveraging Combine. Rejoice!
Additionally, the good news to mention is that there is a compatibility between the Foundation framework and Combine framework. Citing from Combine documentation:
Several Foundation types expose their functionality through publishers, including Timer, NotificationCenter, and URLSession. Combine also provides a built-in publisher for any property that’s compliant with Key-Value Observing.
You can combine the output of multiple publishers and coordinate their interaction. For example, you can subscribe to updates from a text field’s publisher, and use the text to perform URL requests. You can then use another publisher to process the responses and use them to update your app.
This means that it will make our lives easier when it comes to dealing with some of the Foundation types with Combine. I personally hope that we’ll see more of it in the future.
And finally:
As I mentioned before in the SwiftUI article, a declarative paradigm is already popular. Even if it’s new to you, working with it will not only be reflected on your iOS development knowledge, but it will definitely expand your general programming skills, as well as your problem solving skills. When it comes to iOS development, the beauty of it is that we have more dynamic facilities to achieve the desired patterns and approaches, it’s more like “learn it once, apply it anywhere”.
Thanks for reading!
Written by: Ahmad Fayyas
Bio: Full-time iOS developer. If I’m not in front of my PC coding or playing video games, you can find me hanging out with friends, lifting some weights or sleeping!
*Opinion disclaimer: Please note that the views, thoughts, and opinions expressed in the article above belong solely to the author, and not necessarily to Aspire as an organization.