"Receive canceled" 转换 Publisher 时

"Receive canceled" when transform Publisher

我想创建一个模块,它会在需要时刷新令牌并使用来自 Apple 的 Combine 重复最新请求。

目前,每个部分都运行良好,但不是这个:

  public func executeRequest<T: Decodable, E: ServerErrorType>(
    _ request: HTTPRequest,
    mapper: ObjectMapper<T, E>
  ) -> AnyPublisher<(T, HTTPResponse), Error> {
        return authentificator // <- handle refresh token stuff
          .refreshToken(force: false)
          .subscribe(on: DispatchQueue.global())
          .flatMap { token in // <- on obtain token - transform it into request

---> (here)
            session.publisher(for: request, mapper: mapper, token: token) // <- create request 
---> (here)
              .tryCatch({ error -> AnyPublisher<(T, HTTPResponse), Error> in
                if let error = error as? ServerErrorType,
                   error.isAuthError {
                  
                  return authentificator
                    .refreshToken(force: true)
                    .subscribe(on: DispatchQueue.global())
                    .flatMap { token -> AnyPublisher<(T, HTTPResponse), Error> in
                      session.publisher(for: request, mapper: mapper, token: token) //<- repeat if token refreshed
                    }
                    .eraseToAnyPublisher()
                } else {
                  throw error
                }
              })
              .print()
          }
          .receive(on: DispatchQueue.main)
          .print()
          .eraseToAnyPublisher()
   }

在令牌过期时标记 (here) 的地方,tryCatch 将不起作用,而是在控制台中打印“已取消接收”。我不确定我做错了什么。有什么建议吗?

我找到了原因 - 我的 AnyCancellable 设置变为零,因为 ViewModel 由于 root TabBar 重新初始化而变为零,因为 SwiftUI 更新过程。 (我有一个 TabBar 作为另一个 View 中的 OptionalView 是根)

  var body: some View {
    VStack {
      switch viewModel.currentFlow {
        case .onboarding:
          WelcomeView()
            .transition(.opacity)
        case .main:
          MainTabBarView() // <- reinit here cause the issue
            .transition(.opacity)
     }
    }
  }

刷新令牌的代码完全正确,可能的修复方法是:

  • 要么将 @StateObject 用于 ViewModel
@ObservedObject private var viewModel: <MyViewModel>

更新为:

@StateObject private var viewModel: <MyViewModel>
  • 要么在任何重新加载时使用 TabBar 的相同 ☝️ 实例。

可能的修复:

  private lazy let mainTabBar: MainTabBarView = .init() // <- init only once
  private lazy let welcome: WelcomeView = .init()
  
  var body: some View {
    VStack {
      switch viewModel.currentFlow {
        case .onboarding:
          welcome
            .transition(.opacity)
        case .main:
          mainTabBar
            .transition(.opacity)
      }
    }
  }