1-RxSwift中基本概念和使用

2021-08-31  本文已影响0人  一双鱼jn

RxSwit中最重要的一个概念叫做Observable,我们可以把他翻译为序列、可观察序列等等

流、序列、可观察序列,都是一样的东西。就是一个可以持续发出事件的东西。

在Rx中 方法也被称作为 操作符

怎样创建一个信号流

怎样监听一个信号流

在没有RxSwift 我们很熟悉 NotificationCenter,在通知模式中,我们想要监听一个通知会通过addObserver()监听指定的通知。

在RxSwift中和上面很相似,只不过把addObserver()替换成了subscribe()

但是和通知不一样的是,通知我们一般使用的是它的单例,而RxSwift的每一个信号源都是单独的。

如果一个信号没有被订阅的时候,它是不会发送事件的,内部的操作也不会执行的。

监听操作就像是在信号源和观察者之间建立一条通道,监听之后,才会有这条通道,信号源才会通过通道发送事件过来。

这个事件发送就像是一个流。我们可以处理这个事件流中的每一个事件。

通过 subscribe() 方法就可以监听一个信号流,下面是一个示例


    let observable = Observable.of(1, 2, 3)

    observable.subscribe{ event in 

        print(event)

    }

上面的代码会输出


    next(1)

    next(2)

    next(3)

    completed

点击subscribe方法可以看到,它的闭包的参数是一个 Event<Int> 类型的值,每次信号流发送信号,都把值放到Next事件包起来然后发送出来

但是通常我们使用的都是内部包起来的值 ,所以一般可以通过下面方式进行使用


    observable.subscribe { event in 

        if let value = event.element {

            print(value)

        }

    } 

Event 有一个可选性的 element属性,因为只有 Next 事件才会有element,所以可以通过解包来拿到内部的值

因为事件的订阅是经常使用的,每次进行解包有些麻烦,所以Rx提供了一个快捷方法,对于每种事件都有一个操作符进行监听

    
    observable.subscribe {

        onNext: { element in 

            print(element)

        }, 

        onCompleted: {

            print("completed!")

        }

    }

信号流的终止和释放

再提一次:一个信号源如果没有观察者监听,它不会做任何事。

是这个监听的动作触发了信号源的工作,让它一直发送事件,一直到发送了一个error或completed事件才会终止这个信号(信号源和观察者之间就断开了通道,后续的事件就不会受到了)。

除了通过发送 error 或 completed 事件,我们也可以通过取消监听来手动来销毁这个信号源,从而终止事件流。

写一个代码看一下信号流的终止


    let observable = Observable.of("A", "B", "C")

    let subscription = observable.subscribe { event in 

        print(event)

    }

代码解释

  1. 创建了一个字符串的信号流

  2. 监听了这个信号。同时,将这个信号源的返回值Disposable 用一个常量subscription保存了起来

  3. 在闭包里面打印每一个事件

上面的代码并没有将这个信号源进行释放。也就是说这个信号流的所有信号都发送完了,但是在监听者和信号源之间的通道还存在。所以这里是没有意义的。它也会带来内存泄漏的问题。

如果要主动的取消订阅,可以让 销毁器(Disposable类型的subscription) 通过调用 dispose() 方法。当释放了这个信号源之后,它就不会再发送任何事件了。


subscription.dispose()

单独的处理每一个信号的订阅的销毁太麻烦,所以RxSwift提供了一个 DisposeBag 类型

一个DisposeBag 包含了所有的需要等待释放的 disposable

通常通过 disposed(by:)方法将订阅者添加到 这个DisposeBag包中,这个包在释放的时候,会对包中的每一个 订阅者(disposable) 调用 dispose() 方法进行终止信号流的操作。

所以一个通常的模式就是这样

    let disposeBag = DisposeBag()

    Observable.of("A", "B", "C").subscribe{ 

        print($0)

    }.disposed(by: disposeBag)



注释

  1. 先创建一个释放者包

  2. 创建一个信号流

  3. 监听这个信号流,并打印这发送的事件通过默认参数$0

  4. 将返回的disposable添加到释放包里面去

问题来了:这个销毁器是哪里来的?为什么通过subscribe()方法建立了监听之后就可以得到?dipose()方法执行了什么?。

这就要从信号最原始的创建方法 create() 来看

create 方法

之前看过提供的几个创建信号源的方法,都是自动就把事件都发出去了,我们没有主动的控制事件的发送。通过 create 方法就可以手动的发送所有可以使用的事件出去。

create的一个简单示例就是下面这样:


    Observable<String>.create { observer in 

        observer.onNext("1")

        observer.onCompleted()

        return Disposables.create()

    }

create方法的参数是一个闭包,闭包的形参名是 subscribe。那这个闭包什么时候执行。

从create的方法的代码注释中可以看到,这个闭包是 subscribe() 方法的实现。

所以就是说,它是在subscribe()方法执行的会被执行。

也就解释了为什么 一个信号如果没有产生订阅,它是不会执行任何操作的。

接下来 就要看一下这个闭包的参数和返回值

闭包接收一个AnyObserver参数,返回一个Disposable

我们上面介绍信号流的终止的时候看到了 subscribe() 的返回值是一个Disposable ,就是这里创建并返回的这个 Disposable。

AnyObserver 是一个泛型,它的作用就是把将要发送给订阅者的 值 添加到这个信号流中。

onNext() 是 on(.next(_:)) 的一个快捷方式

最后返回一个disposable 表示在这个信号流终止或销毁的时候要做的事情,在这个例子里面没有要清理的东西,所以返回了一个空的disposable

我理解这个 Disposable 和 Observable observer是没有什么关系的。它要做的是一些额外的资源的清理。

如果不发送 completed 或 error 这个信号流是不会停止的,也就不会执行 disposable 的,这个信号就不会被释放。(就是观察者和信号源之间的通道不会断开)

还有哪些方法可以创建信号流

特殊信号

和普通的信号流相比,这些特殊信号的可操作能力更小。通常他们只有一种能力可以执行。

在任何使用特殊信号的地方都可以用普通信号代替。

这些特殊信号就是为了简化代码

在RxSwift中先介绍三种特殊信号: SingleMaybeCompletable

    
        // 定义文件读取错误时的错误类型

        enum FileReadError: Error {

            case fileNotFound, unreadable, encodingFailded

        }



        // 定义一个文件读取的方法 

        func loadDiskFile(path: String) -> Single<String> {

            return Single<String>.create {

                let disposable = Disposables.create()

                guard let path = Bundle.main.path(forResource: path, ofType: "txt") else {

                    single(.error(FileReadError.fileNotFound))

                    return disposable

                }

            
                guard let data = FileManager.default.contents(atPath: path) else {

                    single(.error(FileReadError.unreadable))

                    return disposable

                }


                guard let contents = String(data: data, encoding: .utf8) else {

                    single(.error(FileReadError.encodingFailed))

                    return disposable

                }


                single(.success(contents))

                return disposable

            }

        }


        // 通过Single获取结果 

        loadDiskFile("sample").subscribe(

            switch $0 {

                case .success(let content): 

                    print(content)

                case .error(let error): 

                    print(error)

            }

        ).disposed(by: DisposeBag()) 

后面还会有更多的特殊信号

上面一部分的小总结

到这里,我们在上面介绍的什么是信号流、怎么创建信号,怎么监听信号和怎么在信号释放的做一些事情。

但是上面的这些信号本质是只读的,我们只能监听这些信号,然后得到这些信号产生的事件。(或者说这些信号更像是一次性的,它处理完一些事情后,就把信号发送出来,然后这个信号的作用就结束了。)

在开发的过程中可能我们更通用的需求是:在运行的时候手动的添加一个信号到信号流中发送给监听者。

这就是下面要介绍的 Subject

上一篇 下一篇

猜你喜欢

热点阅读