在不影响发布者类型的情况下向发布者转换链添加额外的逻辑
Add additional logic to chain of publisher transformation without affecting Publisher type
Kotlin 的协程提供了编写非常扁平代码的能力。我正在尝试转换一些异步 iOS 代码以利用 Combine 将其展平。
Kotlin 看起来像:
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 看起来像:
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
}
如何将这种缓存数据的逻辑添加到此 AnyPublisher 中?我想让它在这个逻辑转换过程中缓存。理想情况下,可以有一个 also 函数在订阅者完成事务时附加逻辑。
解法:
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 { [=12=] ? networkCallFlow : localCallFlow }
.eraseToAnyPublisher()
}
你可以用 flatMap
链接它。
如果 cache
也是一个 AnyPublisher<[Job], Error>
会更容易,那么你可以有以下内容:
return isCall
? networkRequest
.flatMap { jobs in cache(jobs) }
.catch{ _ in return localRequest }
.eraseToAnyPublisher()
: localRequest
否则,您需要将其 Void
返回值映射回 jobs
:
return isCall
? networkRequest
.flatMap { jobs in
cache(jobs).map { _ in jobs }
}
.catch{ _ in return localRequest }
.eraseToAnyPublisher()
: localRequest
Kotlin 的协程提供了编写非常扁平代码的能力。我正在尝试转换一些异步 iOS 代码以利用 Combine 将其展平。
Kotlin 看起来像:
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 看起来像:
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
}
如何将这种缓存数据的逻辑添加到此 AnyPublisher 中?我想让它在这个逻辑转换过程中缓存。理想情况下,可以有一个 also 函数在订阅者完成事务时附加逻辑。
解法:
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 { [=12=] ? networkCallFlow : localCallFlow }
.eraseToAnyPublisher()
}
你可以用 flatMap
链接它。
如果 cache
也是一个 AnyPublisher<[Job], Error>
会更容易,那么你可以有以下内容:
return isCall
? networkRequest
.flatMap { jobs in cache(jobs) }
.catch{ _ in return localRequest }
.eraseToAnyPublisher()
: localRequest
否则,您需要将其 Void
返回值映射回 jobs
:
return isCall
? networkRequest
.flatMap { jobs in
cache(jobs).map { _ in jobs }
}
.catch{ _ in return localRequest }
.eraseToAnyPublisher()
: localRequest