ios - RxSwift,我如何链接不同的可观察对象

标签 ios swift alamofire rx-swift

我在 Reactive 编程和 RxSwift 方面仍然是一个初学者。 我想链接两个不同的操作。在我的例子中,我只想从网络服务器下载一个 zip 文件,然后在本地解压缩。 我也想,同时显示下载文件的进度。 所以我开始创建第一个可观察对象:

 class func rx_download(req:URLRequestConvertible, testId:String) -> Observable<Float> {

    let destination:Request.DownloadFileDestination = ...

    let obs:Observable<Float> = Observable.create { observer in
       let request =  Alamofire.download(req, destination: destination)
        request.progress { _, totalBytesWritten, totalBytesExpectedToWrite in
            if totalBytesExpectedToWrite > 0 {
                observer.onNext(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
            }
            else {
                observer.onNext(0)
            }
        }
        request.response {  _, response, _, error in
            if let responseURL = response {
                if responseURL.statusCode == 200 {
                    observer.onNext(1.0)
                    observer.onCompleted()
                } else  {
                    let error = NSError(domain: "error", code: responseURL.statusCode, userInfo: nil)
                    observer.onError(error)
                }
            } else {
                let error = NSError(domain: "error", code: 500, userInfo: nil)
                observer.onError(error)
            }

            }
            return AnonymousDisposable () {
                request.cancel()
            }
        }
    return obs.retry(3)

}

之后,我为解压缩创建了一个类似的函数

class func rx_unzip(testId:String) -> Observable<Float> {
    return Observable.create { observer in
        do {
            try Zip.unzipFile(NSURL.archivePath(testId), destination: NSURL.resourceDirectory(testId), overwrite: true, password: nil)
                {progress in
                    observer.onNext(Float(progress))
                }
        } catch let error {
            observer.onError(error)
        }
        observer.onCompleted()
        return NopDisposable.instance
    }
}

现在我在“ View 模型层”上有这个逻辑,所以我下载->订阅完成->解压

我想要的是将两个 Observable 合二为一,以便先执行下载,然后完成解压文件。有什么办法吗?

最佳答案

Concat运算符需要相同的数据类型

的确,concat运算符允许您强制执行可观察对象的序列,但是使用 concat 可能会遇到一个问题是concat运营商要求 Observable s 具有相同的通用类型。

let numbers     : Observable<Int>    = Observable.from([1,2,3])
let moreNumbers : Observable<Int>    = Observable.from([4,5,6])
let names       : Observable<String> = Observable.from(["Jose Rizal", "Leonor Rivera"])


// This works
numbers.concat(moreNumbers)

// Compile error
numbers.concat(names)

FlatMap 运算符允许您链接 Observable 的序列s

这是一个例子。

class Tag {
    var tag: String = ""
    init (tag: String) {
        self.tag = tag
    }
}

let getRequestReadHTML : Observable<String> = Observable
                            .just("<HTML><BODY>Hello world</BODY></HTML>")

func getTagsFromHtml(htmlBody: String) -> Observable<Tag> {
    return Observable.create { obx in

        // do parsing on htmlBody as necessary

        obx.onNext(Tag(tag: "<HTML>"))
        obx.onNext(Tag(tag: "<BODY>"))
        obx.onNext(Tag(tag: "</BODY>"))
        obx.onNext(Tag(tag: "</HTML>"))

        obx.onCompleted()

        return Disposables.create()
    }
}

getRequestReadHTML
    .flatMap{ getTagsFromHtml(htmlBody: $0) }
    .subscribe (onNext: { e in
        print(e.tag)
    })

注意如何 getRequestReadHTML类型为 Observable<String>而函数 getTagsFromHtml类型为 Observable<Tag> .

使用多个 flatMaps 可以增加发射频率

但是要小心,因为 flatMap运算符接受一个数组(例如 [1,2,3])或一个序列(例如一个 Observable),并将所有元素作为发射发射。这就是为什么已知会产生 1...n 的转换。 .

如果您定义了一个可观察对象,例如网络调用,并且您确定只有一次发射,您将不会遇到任何问题,因为它的转换是 1...1。 (即一个 Observable 对应一个 NSData)。太棒了!

但是,如果你的 Observable 有多个发射,要非常小心,因为链式 flatMap运营商将意味着排放量将呈指数级(?)增加。

一个具体的例子是当第一个 observable 发出 3 次发射时,flatMap 运算符转换 1...n其中 n = 2,这意味着现在总共有 6 个排放量。另一个 flatMap 运算符可以再次转换 1...n其中 n = 2,这意味着现在总共有 12 个排放量。仔细检查这是否是您预期的行为。

关于ios - RxSwift,我如何链接不同的可观察对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35936387/

相关文章:

ios - 为 subview 使用优化 UIScrollView

SWIFT:如何随机选择 5 个障碍物中的 1 个并对其运行一个 Action ,并每秒重复这个过程?

json - 更新结构中的特定值

swift - 如何用Alamofire(帖子)上传图片?

swift - 使用 alamofire 发出 POST 请求

swift - 错误 : Extra parameter in request i used Swift 4. 为什么我必须传递类型为 [String : Any]? 的参数

html - 在同一字符串中使用不同语言的 iOS Safari 中的奇怪行为

ios - 如何在 iOS 中将数组作为参数发送给 json 服务

ios - NSURLConnection 将 SendRequestForAuthenticationChallenge 持久化

swift - Cocoapod podspec 上的预处理器标志