章节2:Observables

现在我们学会了使用RxSwift和一些基本概念,现在我们去学习observables。

在这一章中,我们去创建几个例子练习订阅observables。实际使用可能有点模糊,但是我们可以获得更多的技巧和学习更多的observables类型。这些技巧将在本书中的下部分伴随着你!

Getting started
启动一个命名为RxSwiftPlayground的项目。已经用CocoaPods安装好了RxSwift库。打开Xcode,编译。

通过源文件选择SupportCode.swift文件,它包含以下helper函数示例:

public func example(of description: String, action: () -> Void) {
  print("\n--- Example of:", description, "---")
  action() 
}

在这一章中你将使用这个函数来封装不同的使用列子,很快,您将看到如何使用这个函数。
但是在你深入之前,你可以好好思考一个问题:什么是observable?

什么是observable?
Observables是Rx的核心。你将花一些时间思考observables是什么,怎么创建他们,怎么使用。

你会看到“observable”、“observable sequence,” 和 “sequence” 交替使用。实际上,他们都是一样的。你甚至可以看成特殊从一个时间点到另一个时间点的“流”,尤其是用RxSwift处理不同的响应环境。“流”也指的是同样的事情,但在RxSwift我们称之为sequence不是stream

章节2:Observables_第1张图片
2CBF3FAC-ABFA-472B-9713-E3123CDFCD73.png

一些工作在序列中的事情。一个Observable就是一个序列,包含一些特殊功能。其中之一也是最重要的一点就是,是异步的。Observables产生事件,经过一段时间的发射的过程。事件可以包含值,如数字或一个自定义类型的实例,也可以是公认的手势,比如单击。

概念化这个最好的方法之一是使用图表(这只是在时间轴的标注)。

E854CC06-1D2F-44A7-AE71-16E481AACEE0.png

从左到右的箭头代表时间,圆圈里的数字代表序列里的元素。元素1将会发送,在某个时刻会通过,然后元素2和元素3将会发送。会花费多少时间?它可能贯穿observable的生命周期。让你了解到observable的生命周期。

Lifecycle of an observable
在前面的图表中,observable发送了3个元素。当observable发送一个元素,就已经知道了它的next事件。

下面是另一个图表,时间轴上有一个垂直的块表示observable的终点。

章节2:Observables_第2张图片
98A180E5-EE0B-4256-AF00-EABFBFB2809C.png

observable发送三个单击事件,然后结束。它将调用completed事件来终止。例如,也许单击在传递到view上被遗失了。observable已经终止,不会发送任何事件。这是正常的中断,然而,一些也可能出错。

D9D3F8F9-CAAC-46E7-AE52-BDE612FD3BE7.png

上图中出现了一个错误,用红色的X表示。observable发送一个error事件,这和observable通过completed事件后正常中断没有什么区别。如果observable发送error事件,也会中断不会发送任何事件。

下面是快速回顾:

  • observable发送next事件包含元素,会一直持续:
  • 发送error事件中断,或者
  • 发送completed事件中断。
  • 一旦observable被中断,将不会在发送事件。

通过RxSwift源码看出,这些事件用枚举表示:

/// Represents a sequence event.
///
/// Sequence grammar:
/// **next\* (error | completed)**
public enum Event {
    /// Next element is produced.
    case next(Element)
    /// Sequence terminated with an error.
    case error(Swift.Error)
    /// Sequence completed successfully.
    case completed
}

可以看出,.next事件包含Element。.error事件包含Swift.Error,**.completed **事件只是简单的终止不包含任何数据。

现在你知道observables是什么和做什么的了么,我们将创建observables在事件中来观察。

创建observables
在RxSwift.playground文件中添加如下代码:

example(of: "just, of, from") {
  // 1
  let one = 1
  let two = 2
  let three = 3
  // 2
  let observable: Observable = Observable.just(one)
}

上面的代码做的事情是:
1.定义一些你将用到的数字常量。
2.创建Int型的observable序列用just方法匹配one.

只是适当命名,因为它所做的是创建一个observable序列包含单个元素。只是Observable的一类方法。然而,在Rx中方法归类为“operators”。你可以猜猜哪个方法是正确的。

在example(of:)代码块的末尾添加下面代码:

let observable2 = Observable.of(one, two, three)

这一次你没有显式地指定类型。你可能会认为因为你给它几个整数,Int类型的Observable。Option-click observable2显示其推断的类型,你会发现这是一个Int的Observable,而不是一个数组。

这是因为operator需要一个可变参数的类型推断的元素传递给它。

如果你想创建一个数组的observable,你可以在of中传递数组。代码如下:

let observable3 = Observable.of([one, two, three])

Option-click observable3你将看到实际是一个[Int]的Observable。operator可以传递一个数组或单一元素,看起来可能有点奇怪。然而,数组也是单一元素,而不是内容。

另一个创建observables的操作是from。代码如下:

let observable4 = Observable.from([one, two, three])

from操作需要从数组中创建可见类型的observable,Option-click observable4你将看见Observable的类型是Int而不是[Int]。

此时控制台看起来什么都没有。因为你还没有打印,是时候开始订阅observables了。

订阅observables

作为一个iOS开发,你可能对NotificationCenter非常熟悉;向观察者广播notifications,与RxSwift 的Observables是不同的。下面是观察UIKeyboardDidChangeFrame的notification,处理代码段为:

let observer = NotificationCenter.default.addObserver(
  forName: .UIKeyboardDidChangeFrame,
  object: nil,
  queue: nil
) { notification in
  // Handle receiving notification
}

订阅 RxSwift中的observable非常相似;你可以用observable来订阅它。所以用subscribe()来取代addObserver()。不像NotificationCenter,和单例不同,每个observable都是不同的。

更重要的是,observable直到被订阅了才会发送事件。observable是一个序列的定义;在Swift库中subscribing更像是调用next()事件的迭代:

quence = 0..<3
var iterator = sequence.makeIterator()
while let n = iterator.next() {
  print(n)
}
/* Prints: 
0
1
2 
*/

订阅是这个的改进版。你可以为每个可以发送事件的observable类型添加handlers。回忆observable的.next,.error, 和.completed事件。.next 事件将会传递参数到handler,.error事件包含错误实例。

看下面这个action,编写一个新的例子:

example(of: "subscribe") {
  let one = 1
  let two = 2
  let three = 3
  let observable = Observable.of(one, two, three)
}

这和上一个例子相似,添加下面的代码段到例子中,订阅observable:

observable.subscribe { event in
  print(event)
}

注意看xcode输出区域。
Option-click subscribe,你将看到一个携带Int型事件和无返回值的逃逸闭包,subscribe返回Disposable,稍后将介绍disposables。

章节2:Observables_第3张图片
4D1B692C-31F2-4A58-B693-21AE18A7DFF6.png

打印结果为:

--- Example of: subscribe ---
next(1)
next(2)
next(3)
completed

observable为每个元素发射.next事件,然后发射.completed事件最好中断。在工作中,你通常对.next事件发送的元素更感兴趣而不是事件本身。

看看如何使用它们,用下面的代码替换上面的订阅代码:

observable2.subscribe { (event) in
            if let element = event.element{
                print(element)
            }
        }

事件有一个element属性。是可选值,因为.next事件包含一个element。所以如果element如果不是nil的话你可以可选是否绑定。现在,只是打印出了elements,不是包含elements的事件,也不是.completed事件。

1
2
3

这是一个很好的案例,在RxSwift通常有捷径。这里有subscribe操作符为每个事件类型的observable发送nexterrorcompleted**。用这段代码替换上一段:

observable2.subscribe(onNext: { element in
            print(element)
        })

现在你只处理.next事件,忽略其他,onNext闭包只接收.next事件元素作为参数,所以你不需要像之前那样去检索。

你知道了怎样用一个元素和多个元素创建observable。但是怎么用0个元素创建observable?empty操作符用0个元素创建空的observable序列;只会发射.completed事件。
例子如下:

example(of: "empty") {
  let observable = Observable.empty()
}

observable必须定义一个特殊的类型因为不能推理出来,empty不会推理任何类型,必须自己定义。Void是一个很好的选择。添加下面的代码去订阅它:

observable.subscribe(
// 1
    onNext: { element in
      print(element)
},
// 2
    onCompleted: {
      print("Completed")
} )

这段代码将按一下顺序运行:
1.处理.next事件,和上个例子一样。
2..complete事件不包含元素,所以只是打印出来。
在控制面板,将看到empty仅仅发送.completed事件:

--- Example of: empty ---
Completed

empty observable怎么使用?当你想返回一个立即中断的observable时会很方便,或者只有0个值得时候。

和empty操作符相反的是,never创建的observable不会发射任何事件和中断。它可以被用来表示无穷的时间。示例:

example(of: "never") {
  let observable = Observable.never()
  observable
    .subscribe(
      onNext: { element in
        print(element)
    },
      onCompleted: {
        print("Completed")
    }
) }

没有打印任何东西,连"Completed"都没有。你怎么知道它如何工作?保持好奇直到Challenge部分。

目前,我们只是看到了可见变量,但也有可能是一段值得范围来生成observable。示例:

example(of: "range") {
  // 1
  let observable = Observable.range(start: 1, count: 10)
  observable
    .subscribe(onNext: { i in
  // 2
      let n = Double(i)
      let fibonacci = Int(((pow(1.61803, n) - pow(0.61803, n)) /
2.23606).rounded())
      print(fibonacci)
  })
}

一步一步分解:
1.用range操作符创建一个observable,需要一个开始值和一串连续的整数来生成。
2.对没个发送出来的元素计算和打印nthFibonacc数值

在第七章 “Transforming Operators.”中有一个比onNext更好的方法来转变发送的元素。

除了never()示例,到目前为止observables都是自动发射.completed事件和自然终止。这允许你专注于创建和订阅observables,但是对observables的深入也很重要。

Disposing and terminating
observable直到接收订阅之前都不会做任何事情。是订阅触发了observable了开始发射事件,直到发射.error或.completed然后自然中断。你可以手动取消订阅observable。示例:

example(of: "dispose") {
  // 1
  let observable = Observable.of("A", "B", "C")
  // 2
  let subscription = observable.subscribe { event in
  // 3
    print(event)
  }
}

简短概述为:
1.创建observable。
2.订阅observable,用subscription接收返回值。
3.打印发射的事件。
调用dispose()取消subscription,在取消subscription之后,observable将会停止发射事件,示例:

subscription.dispose()

管理每个subscription会很糟糕,所以RxSwift包含DisposeBag类型。dispose bag 表示一次性的 —— 通常用.addDisposableTo()添加 —— 当dispose bag还未销毁之前它将为每个对象调用dispose()方法。示例:

example(of: "DisposeBag") {
  // 1
  let disposeBag = DisposeBag()
// 2
  Observable.of("A", "B", "C")
    .subscribe { // 3
  print($0) }
    .addDisposableTo(disposeBag) // 4
}

disposable是怎么工作的:
1.创建dispose bag。
2.创建observable。
3.订阅和打印发射的事件。
4.为subscrib添加disposeBag。

这是常用的模式;创建和订阅一个observable然后立即将subscription添加到dispose bag。

为什么要一直使用disposables?如果忘记将subscription添加到dispose bag,或者当subscription完成后再调用dispose,或者一些其他方式造成observable在某点中断,你将可能造成内存泄漏。不要担心你忘记了;Swift编译器将会警告你没有使用disposables。

在前一个例子,创建了一个特殊的.next 事件的observables。另外使用create 操作符创建的observable的所有特殊事件都会发送到subscribers,示例:

example(of: "create") {
  let disposeBag = DisposeBag()
  Observable.create { observer in
  } 
}

create操作符携带了一个单一的参数叫subscribe。它的工作是为observable上的subscribe提供实现。换句话说,它定义了将要发送到subscribers所有的事件。 Option-click create。

章节2:Observables_第4张图片
E3D2A1C0-2374-4CCF-A7E7-8E16EEF37CDB.png

subscribe是一个携带AnyObserver和返回值为Disposable的逃逸闭包。AnyObserver是一个方便在observable序列中添加将要被发送到subscribers的值的泛型类型,改变create的实现:

Observable.create { observer in
  // 1
  observer.onNext("1")
  // 2
  observer.onCompleted()
// 3
  observer.onNext("?")
// 4
  return Disposables.create()
}

一步一步解释为:
1.向observer中添加.next事件。onNext(:)是on(.next(:))的便利方法。
2.向observer中添加.completed事件。onCompleted是on(.completed)的便利方法。
3.向observer中添加.next事件。
4.返回disposable。

你认为第二个onNext参数“?”会被发送到subscribers吗?看看你的猜想是否正确,添加如下代码:

.subscribe(
  onNext: { print($0) },
  onError: { print($0) },
  onCompleted: { print("Completed") },
  onDisposed: { print("Disposed") }
)
.addDisposableTo(disposeBag)

observable已经被订阅和实现了操作,用onNext传递默认参数和onError传递错误参数。结果是首先触发.next事件,然后打印出"Completed" 和 "Disposed" ,第二个.next 事件不会被打印出,因为observable发送的.completed事件 在打印它之前就已经终止了。

--- Example of: create ---
1
Completed
Disposed

如果在observer上添加一个error会发生什么?在上面示例中添加以下代码:

enum MyError: Error {
  case anError
}

创建一个错误类型。添加到observer.onNext 和 observer.onCompleted之间:

observer.onError(MyError.anError)

observable发射一个错误然后终止:

--- Example of: create ---
1
anError
Disposed

如果你发射的不是.completed事件也不是.error事件,也没把subscription添加到disposeBag会发生什么?
注释掉observer.onError,observer.onCompleted, addDisposableTo(disposeBag),实现如下:

example(of: "create") {
  enum MyError: Error {
    case anError
  }
  let disposeBag = DisposeBag()
  Observable.create { observer in
    // 1
    observer.onNext("1")
//    observer.onError(MyError.anError)
    // 2
//    observer.onCompleted()
// 3
    observer.onNext("?")
// 4
    return Disposables.create()
  }
  .subscribe(
    onNext: { print($0) },
    onError: { print($0) },
    onCompleted: { print("Completed") },
    onDisposed: { print("Disposed") }
)
//  .addDisposableTo(disposeBag)
}

这导致了内存泄漏!observable永远不会结束,disposable也永远不会释放。

--- Example of: create ---
1
?

如果你不想这个例子内存泄漏就取消.completed 事件的注释或把subscription添加到disposeBag。

Creating observable factories
更合理的是创建一个observable factories来给每个观察者提供新的observable而不是创建一个observable来等待订阅者。示例:

example(of: "deferred") {
  let disposeBag = DisposeBag()
  // 1
  var flip = false
  // 2
  let factory: Observable = Observable.deferred {
  // 3
  flip = !flip
  // 4
    if flip {
      return Observable.of(1, 2, 3)
} else {
      return Observable.of(4, 5, 6)
    }
  }
}

这做了些什么?
1.创建了一个observable返回的布尔变量flip。
2.用deferred操作符创建了Int型的observable。
3.flip取反,当factory被订阅的时候。
4.根据flip的值返回不同的observables。
事实上,observable factory与常规的observable不能区分出来。添加这段代码来订阅factory4次:

for _ in 0...3 {
  factory.subscribe(onNext: {
    print($0, terminator: "")
  })
  .addDisposableTo(disposeBag)
print() }

每次订阅factory,都会得到相反的observable。显示123,然后是456,每创建一个新的订阅者都会重复:

--- Example of: deferred ---
123
456
123
456

你可能感兴趣的:(章节2:Observables)