如何按顺序执行操作并更新 UI
Posted
技术标签:
【中文标题】如何按顺序执行操作并更新 UI【英文标题】:How can execute operations sequentially and update UI 【发布时间】:2021-11-11 15:53:58 【问题描述】:我正在尝试按顺序执行一堆操作,并在每次操作开始和完成时更新我的 UI(我必须更新操作状态图标颜色)。
在我的(工作)代码下方:
class SyncManager
private let disposeBag = DisposeBag()
// MARK: - Private Init
private init()
// MARK: - Public Constants
static let shared = SyncManager()
let refreshTokenStatus = BehaviorRelay<SyncStatus>(value: .todo)
let updateCatalogDataStatus = BehaviorRelay<SyncStatus>(value: .todo)
let insertDataStatus = BehaviorRelay<SyncStatus>(value: .todo)
let getDataStatus = BehaviorRelay<SyncStatus>(value: .todo)
func startDatabaseSync(completion: @escaping ((Result<Void, Error>) -> Void))
refreshTokenStatus.accept(.todo)
updateCatalogDataStatus.accept(.todo)
insertDataStatus.accept(.todo)
getDataStatus.accept(.todo)
RefreshTokenManager.shared.refreshToken().do(onSuccess: [self]_ in
print("RefreshTokenManager onSuccess")
refreshTokenStatus.accept(.completed)
, onError: [self] error in
print("RefreshTokenManager onError: \(error)")
refreshTokenStatus.accept(.error)
, onSubscribe: [self] in
print("RefreshTokenManager onSubscribe")
refreshTokenStatus.accept(.running)
).asObservable().concatMap result in
UpdateCatalogDataSyncManager.shared.updateCatalogData().do(onSuccess: [self] in
print("UpdateCatalogDataSyncManager onSuccess")
updateCatalogDataStatus.accept(.completed)
, onError: [self] error in
print("UpdateCatalogDataSyncManager onError: \(error)")
updateCatalogDataStatus.accept(.error)
, onSubscribe: [self] in
print("UpdateCatalogDataSyncManager onSubscribe")
updateCatalogDataStatus.accept(.running)
).asObservable().concatMap result in
GetDataSyncManager.shared.getData().do [self] in
print("GetDataSyncManager onSuccess")
getDataStatus.accept(.completed)
onError: [self] error in
print("GetDataSyncManager onError: \(error)")
getDataStatus.accept(.error)
onSubscribe: [self] in
print("GetDataSyncManager onSubscribe")
getDataStatus.accept(.running)
onDispose:
print("GetDataSyncManager onDispose")
.asObservable().concatMap _ in
InsertDataWorkSyncManager.shared.insertData().do [self] in
print("InsertDataWorkSyncManager onSuccess")
insertDataStatus.accept(.completed)
onError: [self] error in
print("InsertDataWorkSyncManager onError: \(error)")
insertDataStatus.accept(.error)
onSubscribe: [self] in
print("InsertDataWorkSyncManager onSubscribe")
insertDataStatus.accept(.running)
onDispose:
print("InsertDataWorkSyncManager onDispose")
.subscribe _ in
print("SyncManager onNext")
onError: error in
print("SyncManager onError: \(error)")
completion(.failure(error))
onCompleted:
print("SyncManager onCompleted")
completion(.success(()))
onDisposed:
print("SyncManager onDisposed")
.disposed(by: disposeBag)
enum SyncStatus
case todo
case completed
case error
case running
case partial
我的ViewController
:
SyncManager.shared.refreshTokenStatus.skip(1).subscribe(onNext: status in
// Update UI
).disposed(by: disposeBag)
SyncManager.shared.updateCatalogDataStatus.skip(1).subscribe(onNext: status in
// Update UI
).disposed(by: disposeBag)
SyncManager.shared.insertDataStatus.skip(1).subscribe(onNext: status in
// Update UI
).disposed(by: disposeBag)
我是RxSwift
的新手(我只使用了一周),所以我想知道是否有更好的方法来实现我的上述目标。
【问题讨论】:
【参考方案1】:这是一个我认为可行的想法。从概念上讲,这是非常必要的,这使得很难转录为 FRP 的功能声明范式。我保留了相同的外部接口,因此它可以作为替代品。
class SyncManager
private init()
static let shared = SyncManager()
let refreshTokenStatus = BehaviorRelay<SyncStatus>(value: .todo)
let updateCatalogDataStatus = BehaviorRelay<SyncStatus>(value: .todo)
let insertDataStatus = BehaviorRelay<SyncStatus>(value: .todo)
let getDataStatus = BehaviorRelay<SyncStatus>(value: .todo)
private let disposeBag = DisposeBag()
func startDatabaseSync(completion: @escaping (Result<Void, Error>) -> Void)
let sync = Sync.startDatabaseSync()
disposeBag.insert(
sync.refreshTokenStatus.bind(to: refreshTokenStatus),
sync.updateCatalogDataStatus.bind(to: updateCatalogDataStatus),
sync.insertDataStatus.bind(to: insertDataStatus),
sync.getDataStatus.bind(to: getDataStatus),
sync.getDataStatus.subscribe(
onError: error in
completion(.failure(error))
,
onCompleted:
completion(.success(()))
)
)
struct Sync
let refreshTokenStatus: Observable<SyncStatus>
let updateCatalogDataStatus: Observable<SyncStatus>
let getDataStatus: Observable<SyncStatus>
let insertDataStatus: Observable<SyncStatus>
static func startDatabaseSync() -> Sync
let refreshTokenStatus = handle(RefreshTokenManager.shared.refreshToken(), after: .just(.completed))
.catchAndReturn(.error)
let updateCatalogDataStatus = handle(UpdateCatalogDataSyncManager.shared.updateCatalogData(), after: refreshTokenStatus)
.catchAndReturn(.error)
let getDataStatus = handle(GetDataSyncManager.shared.getData(), after: updateCatalogDataStatus)
.catchAndReturn(.error)
let insertDataStatus = handle(InsertDataWorkSyncManager.shared.insertData(), after: getDataStatus)
.catchAndReturn(.error)
return Sync(
refreshTokenStatus: refreshTokenStatus,
updateCatalogDataStatus: updateCatalogDataStatus,
getDataStatus: getDataStatus,
insertDataStatus: insertDataStatus
)
func handle(_ operation: Single<Void>, after: Observable<SyncStatus>) -> Observable<SyncStatus>
after
.ignoreElements()
.asCompletable()
.andThen(
operation
.map SyncStatus.completed
.asObservable()
.startWith(SyncStatus.running)
)
.startWith(.todo)
enum SyncStatus
case todo
case completed
case error
case running
如果您要重新安排其余的代码,使其更符合 Rx 风格,那么您可能会变得更简洁...
【讨论】:
谢谢丹尼尔!我想我有很多研究:)disposed(by:disposeBag)失踪了吗? 没有disposeBag.insert()
替换它。
好的!为什么你说我的代码在概念上是命令式的?什么意思?
“函数式反应式编程的本质是在声明时完全指定一个值的动态行为。” -- Heinrich Apfelmus BehaviorRelays,就其性质而言,不指定声明时的动态行为。加入我们的RxSwift slack 进行更深入的讨论。以上是关于如何按顺序执行操作并更新 UI的主要内容,如果未能解决你的问题,请参考以下文章