我刚接触RxSwift,刚刚继承了一个旧的代码库,所以如果这是一个愚蠢的问题,请原谅我.

在代码中,数据在Completables和Observables的帮助下更新.下面是两种方法,粗略地说明了如何做到这一点(出于隐私目的,有点模糊):

// note: `getNewData()` returns an Observable
func refreshData() -> Completable {
    dataManager.getNewData()
        .map { DataRepresentation(fromObject: $0) }
        .take(1)
        .asSingle()
        .flatMapCompletable { data in
            self.storageManager.save(data: data)
        }
}

// STORAGE MANAGER

func save(data: DataRepresentation) -> Completable {
    do {
        // PSEUDOCODE: save the data, emit an event about it if necessary.
        return Completable.completed()
    } catch let error {
        return Completable.error(error)
    }
}

所以,我的问题是:假设getNewData()允许我传递一些参数,这样我就不会每次都得到相同的数据.此外,假设我想调用该方法n次,等待所有调用返回,然后仍然从refreshData()返回一个Complete(不需要更改其签名).这种事情有可能发生吗?我在查.zip号房,但我不确定它是否适用于这里.谢谢.

推荐答案

以下是基于所有 comments 的更新解决方案:

final class Example {
    let dataManager: DataManager
    let storageManager: StorageManager

    init(dataManager: DataManager, storageManager: StorageManager) {
        self.dataManager = dataManager
        self.storageManager = storageManager
    }

    func refreshData() -> Completable {
        let myInputs = [1,2,3]
        return Observable.zip(myInputs.map(dataManager.getNewData))
            .map { $0.map(DataRepresentation.init(fromObject:)) }
            .asSingle()
            .flatMapCompletable { [storageManager] representations in
                storageManager.save(representations)
            }
    }
}

struct DataManager {
    let getNewData: (Int) -> Observable<Data>
}

struct StorageManager {
    let save: ([DataRepresentation]) -> Completable
}

struct DataRepresentation: Equatable {
    let fromObject: Data
}

以下是一个测试工具,它显示了它的工作(带有大量 comments ):

final class ExampleTests: XCTestCase {
    let scheduler = TestScheduler(initialClock: 0)
    // monitors the values sent to DataManager's `getNewData`
    lazy var dataManagerArgs = scheduler.createObserver(Int.self)
    // monitors the values sent to StorageManger's `save`.
    lazy var storageManagerArgs = scheduler.createObserver([DataRepresentation].self)
    // expect to receive an array of three `DataRepresentation` objects one second after the completable is
    //   subscribed to
    let expectedStorageManagerArgs = parseTimeline(
        "-*",
        values: [
            "*": [
                DataRepresentation(fromObject: "A".data(using: .utf8)!),
                DataRepresentation(fromObject: "B".data(using: .utf8)!),
                DataRepresentation(fromObject: "C".data(using: .utf8)!)
            ]
        ])
        .offsetTime(by: 200)

    func test_happy_path() {
        // this DataManager sends either "A", "B", or "C" and then a completed event for each subscription.
        let dataManager = createDataManager(timeline: { "-\($0)|" })

        // this StorageManager sends a completed event after it's subscribed to.
        let storageManager = createStorageManager(timeline: { _ in "-|" })

        let sut = Example(dataManager: dataManager, storageManager: storageManager)
        let result = scheduler.start {
            sut.refreshData() // call `refreshData()` and record the result of the Completable event.
        }

        // expect to receive all three values as `refreshData` is called.
        let expectedDataManagerArgs = parseTimelineEvents("*", values: { _ in [1, 2, 3] }).offsetTime(by: 100)
        XCTAssertEqual(dataManagerArgs.events, expectedDataManagerArgs[0])

        XCTAssertEqual(storageManagerArgs.events, expectedStorageManagerArgs[0])

        // expect for the `refreshData` completable to complete after the `save` completes.
        let expectedResult = parseTimeline("--|", values: { _ in fatalError() }).offsetTime(by: 200)
        XCTAssertEqual(result.events, expectedResult[0])
    }

    func test_getNewData_failure() {
        // this DataManager sends either "A", or "C", and then a completed event for subscriptions 1 and 3.
        //   it sends an error for subscription 2
        let dataManager = createDataManager(timeline: { $0 == 2 ? "-#" : "-\($0)|" })

        // this StorageManager sends a completed event after it's subscribed to.
        let storageManager = createStorageManager(timeline: { _ in "-|" })

        let sut = Example(dataManager: dataManager, storageManager: storageManager)
        let result = scheduler.start {
            sut.refreshData() // call `refreshData()` and record the result of the Completable event.
        }

        // expect to receive all three values as `refreshData` is called.
        let expectedDataManagerArgs = parseTimelineEvents("*", values: { _ in [1, 2, 3] }).offsetTime(by: 100)
        XCTAssertEqual(dataManagerArgs.events, expectedDataManagerArgs[0])

        // a single error from `getNewData` means no save events.
        XCTAssertEqual(storageManagerArgs.events, [])

        // expect for the `refreshData` completable to emit an error when the getNewData fails.
        let expectedResult = parseTimeline("-#", values: { _ in fatalError() }).offsetTime(by: 200)
        XCTAssertEqual(result.events, expectedResult[0])
    }

    func test_save_error() {
        // this DataManager sends either "A", "B", or "C" and then a completed event for each subscription.
        let dataManager = createDataManager(timeline: { "-\($0)|" })

        // this StorageManager sends an error one second after it's subscribed to.
        let storageManager = createStorageManager(timeline: { _ in "-#" })

        let sut = Example(dataManager: dataManager, storageManager: storageManager)
        let result = scheduler.start {
            sut.refreshData() // call `refreshData()` and record the result of the Completable event.
        }

        // expect to receive all three values as `refreshData` is called.
        let expectedDataManagerArgs = parseTimelineEvents("*", values: { _ in [1, 2, 3] }).offsetTime(by: 100)
        XCTAssertEqual(dataManagerArgs.events, expectedDataManagerArgs[0])

        XCTAssertEqual(storageManagerArgs.events, expectedStorageManagerArgs[0])

        // expect for the `refreshData` completable to emit an error when the save fails.
        let expectedResult = parseTimeline("--#", values: { _ in fatalError() }).offsetTime(by: 200)
        XCTAssertEqual(result.events, expectedResult[0])
    }

    func createDataManager(timeline: @escaping (Int) -> String) -> DataManager {
        DataManager(getNewData: scheduler.mock(
            args: dataManagerArgs,
            values: ["1": "A".data(using: .utf8)!, "2": "B".data(using: .utf8)!, "3": "C".data(using: .utf8)!],
            timelineSelector: timeline
        ))
    }

    func createStorageManager(timeline: @escaping ([DataRepresentation]) -> String) -> StorageManager {
        StorageManager(save: { [scheduler, storageManagerArgs] value in
            scheduler.mock(args: storageManagerArgs, values: ["N": ()], timelineSelector: timeline)(value)
                .ignoreElements()
                .asCompletable()
        })
    }
}

Swift相关问答推荐

JSON如何解码空对象

如何返回JSON数据?

在visionOS RealityView中使用.GenerateText时,未显示Reality Composer Promaterial 纹理

使用变量(而非固定)的字符串分量进行Swift正则表达式

CardStack 和 Lottie

当字符串包含 \r\n 时,NSRegularExpression 不起作用

在 Swift 的异步上下文中,如何指示我想要函数的同步版本?

在 SwiftUI 中将属性显式设置为其默认值

SwiftUI:当 currentIndex 值更改时,数组中的第 n 个视图是否已换出?

SwiftUI View .tint(_ Color) 方法不起作用

iOS16 Bug 键盘在表单解雇 SwiftUI 时打破布局

如何在填充上添加 if else 语句? SwiftUI

如何获取 NSRunningApplication 的参数?

找不到接受提供的参数的/的重载

在 UItextfield 的右视图上添加一个按钮,文本不应与按钮重叠

UITableViewCell 不显示 detailTextLabel.text - Swift

Swift中字节数组的NSData

swift中静态函数和单例类的区别

在 xcode8 中找不到 ModuleName-Swift.h 文件

如何在 iOS 上的 Swift 中获取 sharedApplication?