如何按顺序执行操作并更新 UI

How can execute operations sequentially and update UI

我正在尝试按顺序执行一系列操作,并在每次操作开始和结束时更新我的​​ 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的新手(我只用了一个星期)所以我想知道是否有更好的方法来实现我的上述目标。

这是一个我认为可行的想法。它在概念上非常重要,这使得很难转录到 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 风格,那么您可能会使代码更简洁...