ios 为什么Swift的Combine的Map返回Publishers.Map〈Self,T>而不是〈T,Error>

zf9nrax1  于 2022-12-01  发布在  iOS
关注(0)|答案(1)|浏览(221)

我的请求导致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保持以前的发布者类型,但不知何故嵌套在那里。我不知道,任何帮助感谢:)

watbbzwu

watbbzwu1#

如果您习惯于其他ReactiveX风格的库,或者您习惯于对象总是堆分配的语言(如Java、Kotlin或Scala),那么Combine类型可能会让您大吃一惊。
因为Publishers.Map是其上游发布者类型的泛型(在本例中为AnyPublisher<API.Response, API.Error>),所以它可以内联存储其上游发布者,而无需将上游 Package 在an existential container中,或者为上游分配堆存储。
Map还优化了map运算符的连续使用。Combine框架为所有PublisherMap inherits that定义了a map operator。但是Map还定义了合并连续map运算符的a more specialized map operator
下面是一个例子:

import Combine

let foo: AnyPublisher<[String: [String]], Error> = Empty().eraseToAnyPublisher()

let chained = foo
    .map { Array($0.keys) }
    .filter { !$0.isEmpty }
    .map { $0.joined(separator: ", ") }
    .map { "[\($0)]" }
print("chained", type(of: chained))

chained的类型是什么?

Map<
  Filter<
    Map<
      AnyPublisher<
        Dictionary<String, Array<String>>,
        Error
      >,
      Array<String>
    >
  >,
  String
>

注意两件事。尽管我使用了map操作符三次,但类型中只有两个Map。这是因为map的最后一次使用使用了Map类型的专用map操作符,它将map的两次连续使用合并为一个Map示例。
因为MapFilterstruct,所以它们可以存储在堆栈上,或者直接作为其他数据类型的属性内联。
一般来说,Map可能需要在堆中存储它的transform函数,但它不需要执行堆分配来存储它的上游。在上面的例子中,由于传递给mapfilter的参数都没有关闭任何外部变量,Swift可能能够在创建chained值时优化所有堆分配。
这里泛型类型的使用还使编译器对如何构造chained值有了更多的了解,因此它可能能够执行其他优化。
因此,将运算符应用于发布者通常会返回不同类型的发布者。如果您需要编写一个将发布者作为参数的函数,这意味着您应该使函数通用于发布者类型。例如,每个SwiftUI View都有一个带有以下签名的onReceive修饰符:

func onReceive<P>(
    _ publisher: P,
    perform action: @escaping (P.Output) -> Void
) -> some View where P : Publisher, P.Failure == Never

您可以将任何发布者传递给onReceive,只要该发布者的Failure关联类型为Never。因此,您可以将MapFilterAnyPublisher传递给onReceive

相关问题