【问题标题】:Loop over Publisher Combine framework循环发布者组合框架
【发布时间】:2019-10-26 08:21:18
【问题描述】:

我有以下函数来执行 URL 请求:

final class ServiceManagerImpl: ServiceManager, ObservableObject {
    private let session = URLSession.shared

    func performRequest<T>(_ request: T) -> AnyPublisher<String?, APIError> where T : Request {
        session.dataTaskPublisher(for: self.urlRequest(request))
            .tryMap { data, response in
                try self.validateResponse(response)
                return String(data: data, encoding: .utf8)
            }
            .mapError { error in
                return self.transformError(error)
            }
            .eraseToAnyPublisher()
    }
}

有了以下两个函数,我现在可以从对应的ViewModel调用所需的请求:

final class AuditServiceImpl: AuditService {
    private let serviceManager: ServiceManager = ServiceManagerImpl()

    func emptyAction() -> AnyPublisher<String?, APIError> {
        let request = AuditRequest(act: "", nonce: String.randomNumberGenerator)
        return serviceManager.performRequest(request)
    }

    func burbleAction(offset: Int) -> AnyPublisher<String?, APIError> {
        let request = AuditRequest(act: "burble", nonce: String.randomNumberGenerator, offset: offset)
        return serviceManager.performRequest(request)
    }
}
final class AuditViewModel: ObservableObject {
    @Published var auditLog: String = ""
    private let auditService: AuditService = AuditServiceImpl()

    init() {
        let timer = Timer(timeInterval: 5, repeats: true) { _ in
            self.getBurbles()
        }
        RunLoop.main.add(timer, forMode: .common)
    }

    func getBurbles() {
        auditService.emptyAction()
            .flatMap { [unowned self] offset -> AnyPublisher<String?, APIError> in
                let currentOffset = Int(offset?.unwrapped ?? "") ?? 0
                return self.auditService.burbleAction(offset: currentOffset)
            }
            .receive(on: RunLoop.main)
            .sink(receiveCompletion: { [unowned self] completion in
                print(completion)
            }, receiveValue: { [weak self] burbles in
                self?.auditLog = burbles!
            })
            .store(in: &cancellableSet)
    }
}

当我第一次使用self.getBurbles() 时,一切都很好。但是,对于接下来的调用,print(completion) 显示 finished,并且代码不会执行 self?.auditLog = burbles!

我不知道如何循环 getBurbles() 函数并以不同的时间间隔获得响应。

编辑

简而言之整个过程:

  • 我从类初始化器调用getBurbles()
  • getBurbles() 调用 2 个嵌套函数:emptyAction()burbleAction(offset: Int)
  • 这两个函数产生不同的请求并调用performRequest&lt;T&gt;(_ request: T)
  • 最后,我将响应设置为auditLog 变量并显示在SwiftUI

【问题讨论】:

  • 不只是展示一些方法,你能清楚地知道这些方法各自属于哪个类吗?以及上课地点和方式?问题似乎在于您正在重用同一个发布者,但从这里很难判断。
  • @matt 请检查更新版本,希望现在很清楚

标签: swift combine


【解决方案1】:

这里至少有 2 个问题。

首先,当Publisher 出错时,它将永远不会再次生成元素。这是一个问题,因为你想在这里回收Publisher并多次调用它,即使内部Publisher失败。您需要处理flatMap 中的错误,并确保它不会传播到封闭的Publisher。 (即,您可以返回 Result 或其他一些 enum 或元组,指示您应该显示错误状态)。

其次,flatMap 几乎肯定不是您想要的,因为它将合并所有 api 调用并以任意顺序返回它们。如果您想取消任何现有请求并仅显示最新结果,则应使用.map,后跟switchToLatest

【讨论】:

    猜你喜欢
    • 2020-07-01
    • 1970-01-01
    • 2017-09-07
    • 2021-06-11
    • 2019-10-27
    • 2021-10-22
    • 2015-09-05
    • 1970-01-01
    • 2017-12-31
    相关资源
    最近更新 更多