c++ combine使用_如何使用Combine框架查询多个API

c++ combine使用

Note: If you do not want to use Combine right now, you can check out the native approach in this article.

注意:如果您现在不想使用Combine,可以在 本文中 查看本机方法

介绍 (Introduction)

Combine is a new framework developed by Apple that was introduced at WWDC 2019. It is a declarative Swift API for handling asynchronous operations. In other words, it is Apple’s way of doing functional reactive programming. Combine is built on top of the publish-subscribe pattern. If you are familiar with the pattern or any other FRP framework like RxSwift, ReactiveSwift, etc., it will be easier for you to understand.

Combine是Apple开发的新框架,已在WWDC 2019上引入。它是用于处理异步操作的声明性Swift API。 换句话说,这是苹果公司进行功能性React式编程的方式。 合并是建立在发布-订阅模式之上的。 如果您熟悉该模式或任何其他FRP框架(如RxSwift,ReactiveSwift等),将更容易理解。

I am not going to introduce publishers, subscribers, or subjects. If you do not know anything about them, you should read about them first. I am going to jump to code directly. However, I have provided some Combine resources at the end of this article.

我不会介绍发布者,订阅者或主题。 如果您对它们一无所知,则应先阅读它们。 我将直接跳转到代码。 但是,我在本文末尾提供了一些Combine资源。

According to Apple Developer, Combine “provides a declarative Swift API for processing values over time.”

根据Apple Developer的说法,Combine“提供了声明性的Swift API,用于随时间推移处理值。”

You can find the sample project below:

您可以在下面找到示例项目:

DispatchWorkItem and DispatchGroup are used in the master branch. I have created another branch for Combine. Can you guess its name? It is Combine. I will convert the sample project to Combine step by step.

在master分支中使用DispatchWorkItemDispatchGroup 。 我为合并创建了另一个分支。 你能猜出它的名字吗? 它是合并。 我将逐步将示例项目转换为Combine。

第1步 (Step 1)

We are going to need a method that makes network requests. Luckily, Apple has already built a method (dataTaskPublisher) that returns a publisher. In a real-world app, this method might not be enough. Normally, you would do more error-checking, transforming error messages, interceptors, or you might have plug-ins, etc.

我们将需要一种发出网络请求的方法。 幸运的是,Apple已经建立了一个返回发布者的方法( dataTaskPublisher )。 在实际应用中,此方法可能还不够。 通常,您将执行更多的错误检查,转换错误消息,拦截器,或者您可能具有插件等。

In order to keep the code simple, I will leave it like this:

为了使代码简单,我将这样保留它:

第2步 (Step 2)

I will add another method to my ImageService protocol, and it will return a publisher. You might notice the Never keyword. Basically, it means that it will not fail. I did this because I will replace error with an empty array of strings. This method will be called from our ViewModel:

我将向我的ImageService协议添加另一个方法,它将返回一个发布者。 您可能会注意到Never关键字。 基本上,这意味着它不会失败。 我这样做是因为我将error替换为空字符串数组。 该方法将从我们的ViewModel中调用:

func search(_ query: String) -> AnyPublisher<[String], Never>

Let’s implement the code in the service layer. We are just going to transform UnsplashResponse into a string array and replace any error with an empty array.

让我们在服务层中实现代码。 我们只是要将UnsplashResponse转换为字符串数组,然后将任何错误替换为空数组。

Now, we can call this method in our ViewModel. Let’s change the code in the ViewModel:

现在,我们可以在ViewModel中调用此方法。 让我们在ViewModel中更改代码:

Let’s pause for a while here. We have just changed the search method in our ViewModel. At this point, you can run the project and see the result. However, it does not do the same job as it does in the master branch because we are only querying the first service (services.first?). Don’t worry, we will change that later. We call completion that comes from the View Controller. Therefore, we don’t have to change any code in the View Controller. Cancellable is a protocol that indicates that a process can be cancelled. The cancellable in our code is actually AnyCancellable. You need a strong reference to the result of the sink method. Otherwise, ARC will clean it up and you won’t see anything.

让我们在这里暂停片刻。 我们刚刚更改了ViewModel中的search方法。 此时,您可以运行项目并查看结果。 但是,它不会执行与master分支相同的工作,因为我们只查询第一个服务( services.first? )。 不用担心,我们稍后会更改。 我们称completion来自视图控制器。 因此,我们不必在View Controller中更改任何代码。 Cancellable是一个协议,表示一个过程可以被抵消。 该cancellable在我们的代码实际上是AnyCancellable 。 您需要强烈参考接收sink方法的结果。 否则,ARC将清除它,您将看不到任何内容。

There is one more difference, and that is a delay. We are not delaying our requests. So, let’s implement those missing parts in a Combine style and use a publisher when updating the View Controller.

还有一个区别,那就是延迟。 我们不会延迟我们的要求。 因此,让我们以合并样式实现那些缺少的部分,并在更新View Controller时使用发布者。

Implement this in the View Controller:

在视图控制器中实现:

func updateSearchResults(for searchController: UISearchController) {
viewModel.query = searchController.searchBar.text ?? ""
}

Instead of this:

代替这个:

第三步 (Step 3)

Let’s change our ViewModel:

让我们更改我们的ViewModel:

Well, that is it. Now, we have less code than the sample project built with DispatchWorkItem and DispatchGroup. See the published keyword? That is another fancy feature that comes with property wrappers and Combine. Every time you set a value to query, it will emit those values:

好吧,就是这样。 现在,与使用DispatchWorkItemDispatchGroup构建的示例项目相比,我们的代码更少。 看到published关键字了吗? 这是属性包装器和Combine附带的另一个精美功能。 每次您为query设置一个值时,它将发出这些值:

query = "a"
query = "ab"
query = "abc"

We have two @Published values, one for the ViewController (so that it can observe imageUrls) and another for the ViewModel. We use a wrapper publisher to access $query, which allows us to filter the stream and delay it:

我们有两个@Published值,一个用于ViewController(以便它可以观察imageUrls ),另一个用于ViewModel。 我们使用包装器发布者访问$query ,这使我们可以过滤流并延迟它:

$query.filter{ $0.count > 3 } // filter if character count is less than 4

We do not have to return an empty string array or cancel any requests if the character count is smaller than four because we will not be triggering any action beforehand. We can add a delay with one line of code:

如果字符数少于四个,我们不必返回空字符串数组或取消任何请求,因为我们不会事先触发任何操作。 我们可以用一行代码添加延迟:

.debounce(for: .seconds(1), scheduler: RunLoop.main)

Our wrapper is ready.

我们的包装器准备好了。

Here is where all the magic happens. We query every service in the Services array and merge all requests in another publisher. This new publisher waits for a response from each service. Finally, we have to flatten our result because the merging operation transforms our data. That is it.

这是所有魔术发生的地方。 我们查询Services数组中的每个服务,并将所有请求合并到另一个发布者中。 该新发布者正在等待每个服务的响应。 最后,由于合并操作会转换我们的数据,因此我们必须弄平结果。 这就对了。

结论 (Conclusion)

Combine is a new framework. Despite limitations like iOS 13.0+, it will become more popular and powerful. Timer, URLSession, and NotificationCenter have already adopted the Combine framework. Day after day, more APIs will follow this trend. In my opinion, we will see lots of SwiftUI and Combine in the future. I think you will love it the more you use it and you will keep loving it until you hate it. If you are a lone wolf, you might not hate it that much.

合并是一个新框架。 尽管有iOS 13.0+之类的限制,它仍将变得越来越流行和强大。 Timer,URLSession和NotificationCenter已经采用了Combine框架。 日复一日,更多的API将遵循这种趋势。 我认为,将来我们会看到许多SwiftUI和Combine。 我认为您使用它的次数越多,就会爱上它,并且您会一直喜欢它,直到您讨厌它为止。 如果您是孤独的狼,您可能不会那么讨厌它。

Thank you for reading. Any feedback would be appreciated. Please get in touch if you have any questions.

感谢您的阅读。 对于任何反馈,我们都表示感谢。 如有任何疑问,请与我们联系。

资源资源 (Resources)

翻译自: https://medium.com/better-programming/how-to-query-multiple-apis-with-the-combine-framework-1c4e0298418e

c++ combine使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值