Loop over Publisher Combine рамки - PullRequest
1 голос
/ 25 октября 2019

У меня есть следующая функция для выполнения запроса 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()
    }
}

Имея эти 2 следующие функции, теперь я могу вызывать нужные запросы из соответствующих 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<T>(_ request: T)
  • Наконец, я устанавливаю ответ в auditLog переменная и показать его на SwiftUI слое

1 Ответ

1 голос
/ 26 октября 2019

Здесь как минимум 2 вопроса.

Во-первых, когда Publisher выдает ошибку, он больше никогда не произведет элементы. Это проблема здесь, потому что вы хотите перезапустить издатель здесь и вызывать его много раз, даже если внутренний Publisher не работает. Вам нужно обработать ошибку внутри flatMap и убедиться, что она не распространяется на вмещающую Publisher. (т. е. вы можете вернуть Result или какой-либо другой enum или кортеж, который указывает на то, что вы должны отобразить состояние ошибки).

Во-вторых, flatMap почти наверняка не то, что вы хотите здесь, так как он объединитсявсе вызовы API и вернуть их в произвольном порядке. Если вы хотите отменить любые существующие запросы и показывать только самые последние результаты, вы должны использовать .map, за которым следует switchToLatest .

...