您的位置:首页 > 编程语言 > C语言/C++

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

2020-07-26 13:31 881 查看

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分支中使用

DispatchWorkItem
DispatchGroup
。 我为合并创建了另一个分支。 你能猜出它的名字吗? 它是合并。 我将逐步将示例项目转换为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:

好吧,就是这样。 现在,与使用

DispatchWorkItem
DispatchGroup
构建的示例项目相比,我们的代码更少。 看到
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使用

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: