第十章 其他操作符

311 阅读1分钟

至此,在《Combine: Asynchronous Programming with Swift》书中的操作符讲解已经结束了,但其实还有些操作符没有被讲解到。我们会在此一一列出。

Encoding & Decoding

encode(encoder:)

使用指定的编码器对来自上游的输出进行编码。 使用 encode(encoder:) 和 JSONEncoder,将 Encodable 结构编码为可用于生成 JSON 字符串的数据。

注意:如果您尝试将可选类型传递给 encode 运算符。这会导致编译器出错。

我们看下Apple官方文档的例子:

struct Article: Codable {
    let title: String
    let author: String
    let pubDate: Date
}

let dataProvider = PassthroughSubject<Article, Never>()
let cancellable = dataProvider
    .encode(encoder: JSONEncoder())
    .sink(receiveCompletion: { print ("Completion: \($0)") },
          receiveValue: {  data in
            guard let stringRepresentation = String(data: data, encoding: .utf8) else { return }
            print("Data received \(data) string representation: \(stringRepresentation)")
    })

dataProvider.send(Article(title: "My First Article", author: "Gita Kumar", pubDate: Date()))

运行playground,得到结果:

Data received 79 bytes string representation: {"title":"My First Article","author":"Gita Kumar","pubDate":656324569.12053096}

在上面代码中,encode(encoder:) 运算符将符合Codable协议的 Article 结构,转为了 JSON 字符串。

我们可以尝试屏蔽掉encode这行,并将sink闭包内容改为:

.sink(receiveCompletion: { print ("Completion: \($0)") },
          receiveValue: { print($0) })

再运行playground,得到结果:

Article(title: "My First Article", author: "Gita Kumar", pubDate: 2021-10-19 08:25:41 +0000)

可以比较两次打印的内容,能更清晰的看出encode生成的是JSON类型的数据。

decode(type:decoder:)

使用指定的解码器解码来自上游的输出。

将 decode(type:decoder:) 与 JSONDecoder一起使用可解析JSON类型数据,并解析为指定的数据结构。

我们将encode的代码修改下,替换encode为decode:

struct Article: Codable {
    let title: String
    let author: String
    let pubDate: Date
}

let dataProvider = PassthroughSubject<Data, Never>()
var cancellable = dataProvider
    .decode(type: Article.self, decoder: JSONDecoder())
    .sink(receiveCompletion: { print ("Completion: \($0)")},
          receiveValue: { print ("value: \($0)") })

dataProvider.send(Data("{\"pubDate\":1574273638.575666, \"title\" : \"My First Article\", \"author\" : \"Gita Kumar\" }".utf8))

运行playground,得到结果:

value: Article(title: "My First Article", author: "Gita Kumar", pubDate: 2050-11-20 18:13:58 +0000)

在decode中,将解析后的类型,设置为Article,(代码中用Article.self表示)。 用PassthroughSubject发送一个JSON数据

{"pubDate":1574273638.575666, "title" : "My First Article", "author" : "Gita Kumar" }

最后,经过decode,我们得到了Article的数据。

Debugging

breakpoint

breakpoint提供一个闭包,当闭包需要停止调试器中的进程时,发出一个调试器信号。

breakpoint的函数声明为:

func breakpoint(receiveSubscription: ((Subscription) -> Bool)? = nil, receiveOutput: ((Self.Output) -> Bool)? = nil, receiveCompletion: ((Subscribers.Completion<Self.Failure>) -> Bool)? = nil) -> Publishers.Breakpoint<Self>

参数说明:

  • receiveSubscription 当发布者收到订阅时执行的闭包。闭包返回 true 会触发 SIGTRAP,或返回 false 以继续。
  • receiveOutput 当发布者收到一个值时执行的闭包。闭包返回 true 会触发 SIGTRAP,或返回 false 以继续。
  • receiveCompletion 当发布者收到completion时执行的闭包。闭包返回 true会触发 SIGTRAP,或返回 false 以继续。

我们看下Apple官方文档的代码示例:

let publisher = PassthroughSubject<String?, Never>()
var cancellable = publisher
    .breakpoint(
        receiveOutput: { value in return value == "DEBUGGER" }
    )
    .sink { print("\(String(describing: $0))" , terminator: " ") }

publisher.send("DEBUGGER")

运行playground,会发现代码报错:

error: Execution was interrupted, reason: signal SIGTRAP.

breakpoint的闭包中,我们返回了一个等式value == "DEBUGGER",当我们用PassthroughSubject发布一个“DEBUGGER”时,等式结果为true,所以触发了SIGTRAP