我的请求导致AnyPublisher
let foo: AnyPublisher<API.Response, API.Error> = APIClient.get(API.Endpoints.Demo)
现在我想将这个publisher的值Map到字符串数组,API中的message
。响应的类型是[String : [String]]
,所以我的try是
foo.map { $0.message.map { $0.key } }
此时,我希望最终得到AnyPublisher<[String], API.Error>
,或者只是参数化为<[String], API.Error>
的任何其他发布者,
结果是Publishers.Map<AnyPublisher<API.Response, API.Error>, [String]>
。
func map<T>(_ transform: @escaping (Self.Output) -> T) -> Publishers.Map<Self, T>
上面的.map
函数的文档是正确的,但是为什么它是这样工作的-为什么有人希望Map保持以前的发布者类型,但不知何故嵌套在那里。我不知道,任何帮助感谢:)
1条答案
按热度按时间watbbzwu1#
如果您习惯于其他ReactiveX风格的库,或者您习惯于对象总是堆分配的语言(如Java、Kotlin或Scala),那么Combine类型可能会让您大吃一惊。
因为
Publishers.Map
是其上游发布者类型的泛型(在本例中为AnyPublisher<API.Response, API.Error>
),所以它可以内联存储其上游发布者,而无需将上游 Package 在an existential container中,或者为上游分配堆存储。Map
还优化了map
运算符的连续使用。Combine框架为所有Publisher
和Map
inherits that定义了amap
operator。但是Map
还定义了合并连续map
运算符的a more specializedmap
operator。下面是一个例子:
chained
的类型是什么?注意两件事。尽管我使用了
map
操作符三次,但类型中只有两个Map
。这是因为map
的最后一次使用使用了Map
类型的专用map
操作符,它将map
的两次连续使用合并为一个Map
示例。因为
Map
和Filter
是struct
,所以它们可以存储在堆栈上,或者直接作为其他数据类型的属性内联。一般来说,
Map
可能需要在堆中存储它的transform
函数,但它不需要执行堆分配来存储它的上游。在上面的例子中,由于传递给map
和filter
的参数都没有关闭任何外部变量,Swift可能能够在创建chained
值时优化所有堆分配。这里泛型类型的使用还使编译器对如何构造
chained
值有了更多的了解,因此它可能能够执行其他优化。因此,将运算符应用于发布者通常会返回不同类型的发布者。如果您需要编写一个将发布者作为参数的函数,这意味着您应该使函数通用于发布者类型。例如,每个SwiftUI
View
都有一个带有以下签名的onReceive
修饰符:您可以将任何发布者传递给
onReceive
,只要该发布者的Failure
关联类型为Never
。因此,您可以将Map
、Filter
或AnyPublisher
传递给onReceive
。