Kotlin’s coroutines provide the ability to write very flat code. I am trying to work on converting some of the async iOS code to utilize Combine to flatten it out on my end as well.
Kotlin looks like:
private suspend fun getData(
networkCall: Boolean = true,
networkRequest: suspend () -> Either<FieldError, List<JobModel>>,
localRequest: suspend () -> Either<FieldError, List<JobModel>>,
cache: suspend (data: List<JobModel>) -> Unit
): Either<FieldError, List<JobModel>> {
// getting of Jobs and passing in pair if result was from network
var resultNetwork = false
var result: Either<FieldError, List<JobModel>> = Left(GenericError)
if (!networkCall) {
result = localRequest()
}
// if it was not a network call and failed we will force network call
if (networkCall || result.isLeft()) {
resultNetwork = true
result = networkRequest()
}
if (result is Either.Right && resultNetwork) {
cache(result.b)
}
return result
}
Swift WIP looks like:
public func getData(isNetworkCall: AnyPublisher<Bool, Error>,
networkRequest: AnyPublisher<[Job], Error>,
localRequest: AnyPublisher<[Job], Error>,
cache: ([Job]) -> AnyPublisher<Void, Error>) -> AnyPublisher<[Job], Error>? {
let getJobsRequest = isNetworkCall.flatMap { (isCall) in
return isCall
? networkRequest
//.also { jobs in cache(jobs) }
.catch{ _ in return localRequest }
.eraseToAnyPublisher()
: localRequest
}.eraseToAnyPublisher()
return getJobsRequest
}
How do I add this logic of caching data as part of this AnyPublisher? I would like to have it cache in the midst of this logic transformation. Ideally there could be an also function that appends logic when the transaction is being completed by the subscriber.
Solution:
private func getData(isNetworkCall: AnyPublisher<Bool, Error>,
networkRequest: AnyPublisher<[Job], Error>,
localRequest: AnyPublisher<[Job], Error>,
cache: @escaping ([Job]) -> AnyPublisher<Void, Error>) -> AnyPublisher<[Job], Error> {
// Sequence of steps for when we should do a network call
let networkCallFlow = networkRequest
.flatMap { jobs in // cache jobs from network
cache(jobs)
.replaceError(with: ()) // fire and forget cache, replace error with Void to continue
.map { _ in jobs } // need to give back jobs to flatMap
.setFailureType(to: Error.self) // match failure type
}
.catch { _ in localRequest } // return local if network fails
.eraseToAnyPublisher()
// Sequence of steps for when we should get from local
let localCallFlow = localRequest
.catch { _ in networkCallFlow } // do network flow if local call fails
.eraseToAnyPublisher()
return isNetworkCall
.flatMap { $0 ? networkCallFlow : localCallFlow }
.eraseToAnyPublisher()
}
question from:
https://stackoverflow.com/questions/65831741/add-additional-logic-to-chain-of-publisher-transformation-without-affecting-publ 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…