此源码解析适用于
0.41.0
之前的版本。最新的源码已经把Reducer
重构成了一个协议ReducerProtocol
,但核心的实现方法还是离不开这个版本的源码。
这个扩展的作用是将 Effect
副作用导致的 UI 变化以指定的动画展现。
extension Effect {
// 用指定的动画执行 Effect
public func animation(_ animation: Animation? = .default) -> Self {
switch self.operation {
case .none:
return .none
case let .publisher(publisher):
// 把 `publisher` 包装在 `AnimatedPublisher` 中,
// 使 `publisher` 在指定的动画下发出每一个值。
// 下面有对 `AnimatedPublisher ` 的仔细讲解。
return Self(
operation: .publisher(
AnimatedPublisher(upstream: publisher, animation: animation).eraseToAnyPublisher()
)
)
case let .run(priority, operation):
// 返回一个新的 `run`,使用 `withAnimation` 包装 `send(value)`
return Self(
operation: .run(priority) { send in
await operation(
Send { value in
withAnimation(animation) {
send(value)
}
}
)
}
)
}
}
}
// `AnimatedPublisher` 实现 `Publisher` 协议,并且其上游 `Upstream` 是一个 `Publisher`
private struct AnimatedPublisher<Upstream: Publisher>: Publisher {
// 输出和错误类型与上游相同
typealias Output = Upstream.Output
typealias Failure = Upstream.Failure
// 保存上游和动画类型
var upstream: Upstream
var animation: Animation?
// `Publisher` 协议的方法,收到订阅者
func receive<S: Combine.Subscriber>(subscriber: S)
where S.Input == Output, S.Failure == Failure {
// 自定义的订阅者类型
let conduit = Subscriber(downstream: subscriber, animation: self.animation)
// 将订阅者转发给上游 `Publisher`
self.upstream.receive(subscriber: conduit)
}
// 自定义的订阅者类型
private class Subscriber<Downstream: Combine.Subscriber>: Combine.Subscriber {
// 输入和错误类型与下游 `Subscriber` 相同
typealias Input = Downstream.Input
typealias Failure = Downstream.Failure
// 保存上游和动画类型
let downstream: Downstream
let animation: Animation?
init(downstream: Downstream, animation: Animation?) {
self.downstream = downstream
self.animation = animation
}
func receive(subscription: Subscription) {
// 收到订阅,转发给下游
self.downstream.receive(subscription: subscription)
}
func receive(_ input: Input) -> Subscribers.Demand {
// 收到输入,转发给下游。
// `AnimatedPublisher` 最核心的就是用 `withAnimation` 包装转发输入的操作,
// 使得下游以动画的形式收到输入。
withAnimation(self.animation) {
self.downstream.receive(input)
}
}
func receive(completion: Subscribers.Completion<Failure>) {
// 收到 completion,转发给下游
self.downstream.receive(completion: completion)
}
}
}