RxSwift 样例一 imagePicker

庄宇
2023-12-01

RxSwift简介

RxSwift 是swift原生的reactive响应式开发库。git地址为 https://github.com/ReactiveX/RxSwift。与RxJava,RxPhp是统一家族。
git代码clone后,打开workspace,编译一下(注意要选择mac),然后通读一遍playground里面的代码实例,就会明白它的基本API用法。如果英文不好的同学可以在其他博客里面找到介绍这些API的文章,例如http://blog.csdn.net/Hello_Hwc/article/details/51859330。本文就不再叙述API用法问题,这篇博客是用于介绍RxExample下的Examples。

imagePicker

在ImagePickerController的代码中,我们只需要理解一段代码就可以

cameraButton.rx.tap
            .flatMapLatest { [weak self] _ in
                return UIImagePickerController.rx.createWithParent(self) { picker in
                    picker.sourceType = .camera
                    picker.allowsEditing = false
                }
                .flatMap { $0.rx.didFinishPickingMediaWithInfo }
                .take(1)
            }
            .map { info in
                return info[UIImagePickerControllerOriginalImage] as? UIImage
            }
            .bind(to: imageView.rx.image)
            .disposed(by: disposeBag)

cameraButton.rx.tap,RxSwift封装了原生类的Rx库RxCocoa,例如button的点击事件转化为事件队列并监听事件。这样对于原生的类就可以直接用封装好的rx套件。使用方法就是上图的 原生类.rx。cameraButton.rx是button的扩展,所以有button的对应相应事件,tap就对应touchUpInside。

flatMapLatest 我理解为转化再输入,官方文档的介绍为:Projects each element of an observable sequence into a new sequence of observable sequences and then
transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence.
每个元素变成事件序列再输入到当前序列中。
flatMapLatest()与flatMap()的区别在于,它仅仅将最新激活的元素序列 中的元素,输出到目标序列中。
所以flatMapLatest{}里面也是一个事件序列
return UIImagePickerController.rx.createWithParent(self) { picker in
picker.sourceType = .camera
picker.allowsEditing = false
.flatMap { $0.rx.didFinishPickingMediaWithInfo }
.take(1)

注意这个序列是嵌套在tap序列里面的。take是指取一次,因为iOS的图片选取库在取图的时候,当你指定尺寸时,可能会返回俩个图片,一个是你指定尺寸,一个是原始尺寸。这个情况发生在指定尺寸本来没有的情况下。

.map 会把元素转化成想要的类型,即UIImage
.bind 会绑定元素和控件
.disposed 是资源的回收

可以看到整个过程像伪代码一样流程。
createWithParent 这个方法不是原生的,而是在UIImagePickerController+RxCreate里面封装的。

extension Reactive where Base: UIImagePickerController {
    static func createWithParent(_ parent: UIViewController?, animated: Bool = true, configureImagePicker: @escaping (UIImagePickerController) throws -> () = { x in }) -> Observable<UIImagePickerController> {
        return Observable.create { [weak parent] observer in
            let imagePicker = UIImagePickerController()
            let dismissDisposable = imagePicker.rx
                .didCancel
                .subscribe(onNext: { [weak imagePicker] in
                    guard let imagePicker = imagePicker else {
                        return
                    }
                    dismissViewController(imagePicker, animated: animated)
                })

            do {
                try configureImagePicker(imagePicker)
            }
            catch let error {
                observer.on(.error(error))
                return Disposables.create()
            }

            guard let parent = parent else {
                observer.on(.completed)
                return Disposables.create()
            }

            parent.present(imagePicker, animated: animated, completion: nil)
            observer.on(.next(imagePicker))

            return Disposables.create(dismissDisposable, Disposables.create {
                    dismissViewController(imagePicker, animated: animated)
                })
        }
    }

这个方法接受三个参数,返回一个可观察的UIImagePickerController类。

 let dismissDisposable = imagePicker.rx
                .didCancel
                .subscribe(onNext: { [weak imagePicker] in
                    guard let imagePicker = imagePicker else {
                        return
                    }
                    dismissViewController(imagePicker, animated: animated)
                })

这里是我读的时候最困难的地方。didCancel 是UIImagePickerController的rx属性,可以看到它只有俩个属性,didCancel和didFinishPickingMediaWithInfo。其中didFinishPickingMediaWithInfo可以返回取到的图片。
那么这句代码的意思是订阅imagePicker的cancel事件然后判断当前imagePicker是否创建成功,不成功return,成功就消失controller。

         do {
                try configureImagePicker(imagePicker)
            }
            catch let error {
                observer.on(.error(error))
                return Disposables.create()
            }

            guard let parent = parent else {
                observer.on(.completed)
                return Disposables.create()
            }

这些是判断传入的参数是否有误,本样例里面configureImagePicker并没有传入,而是取了一个默认值。
try是不成功的。如果parent不存在,信号也就不继续传递。

判断都成功,就继续执行,parent推出imagePicker。信号传递.on(.next(imagePicker))

最后返回一个遵守Disposable协议的对象,因为整个函数是在return Observable.create 这个大闭包里面包着的。
这里我觉得他给的写法是创建一个信号,包含取消的事件和完成的事件。但是我发现// return Disposables.create(dismissDisposable, Disposables.create {
// dismissViewController(imagePicker, animated: animated)
// })
//
return Disposables.create {
dismissViewController(imagePicker, animated: animated)
}

这样写完全没有任何不同。有知道的同学欢迎留言。

整理一下这个函数,即创建了一个可监听事件{判断参数有无错误,返回信号(可被监听)}

 类似资料: