# Signal

**Signal** 和 [Driver](/rxswift/rxswift_core/observable/driver.md) 相似，唯一的区别是，[Driver](/rxswift/rxswift_core/observable/driver.md) **会**对新观察者回放（重新发送）上一个元素，而 **Signal** **不会**对新观察者回放上一个元素。

他有如下特性:

* 不会产生 `error` 事件
* 一定在 `MainScheduler` 监听（主线程监听）
* [共享附加作用](/rxswift/recipes/share_side_effects.md)

现在，我们来看看以下代码是否合理：

```swift
let textField: UITextField = ...
let nameLabel: UILabel = ...
let nameSizeLabel: UILabel = ...

let state: Driver<String?> = textField.rx.text.asDriver()

let observer = nameLabel.rx.text
state.drive(observer)

// ... 假设以下代码是在用户输入姓名后运行

let newObserver = nameSizeLabel.rx.text
state.map { $0?.count.description }.drive(newObserver)
```

这个例子只是将用户输入的姓名绑定到对应的标签上。当用户输入姓名后，我们创建了一个新的观察者，用于订阅姓名的字数。那么问题来了，订阅时，展示字数的标签会立即更新吗？

嗯、、、 因为 [Driver](/rxswift/rxswift_core/observable/driver.md) 会对新观察者回放上一个元素（当前姓名），所以这里是会更新的。在对他进行订阅时，标签的默认文本会被刷新。这是合理的。

那如果我们用 [Driver](/rxswift/rxswift_core/observable/driver.md) 来描述点击事件呢，这样合理吗？

```swift
let button: UIButton = ...
let showAlert: (String) -> Void = ...

let event: Driver<Void> = button.rx.tap.asDriver()

let observer: () -> Void = { showAlert("弹出提示框1") }
event.drive(onNext: observer)

// ... 假设以下代码是在用户点击 button 后运行

let newObserver: () -> Void = { showAlert("弹出提示框2") }
event.drive(onNext: newObserver)
```

当用户点击一个按钮后，我们创建一个新的观察者，来响应点击事件。此时会发生什么？[Driver](/rxswift/rxswift_core/observable/driver.md) 会把上一次的点击事件回放给新观察者。所以，这里的 `newObserver` 在订阅时，就会接受到上次的点击事件，然后弹出提示框。这似乎不太合理。

因此像这类型的**事件序列**，用 [Driver](/rxswift/rxswift_core/observable/driver.md) 建模就不合适。于是我们就引入了 **Signal**:

```swift
...

let event: Signal<Void> = button.rx.tap.asSignal()

let observer: () -> Void = { showAlert("弹出提示框1") }
event.emit(onNext: observer)

// ... 假设以下代码是在用户点击 button 后运行

let newObserver: () -> Void = { showAlert("弹出提示框2") }
event.emit(onNext: newObserver)
```

在同样的场景中，**Signal** 不会把上一次的点击事件回放给新观察者，而只会将订阅后产生的点击事件，发布给新观察者。这正是我们所需要的。

## 结论

一般情况下**状态序列**我们会选用 [**Driver**](/rxswift/rxswift_core/observable/driver.md) 这个类型，**事件序列**我们会选用 **Signal** 这个类型。

## 参考

* [Driver](/rxswift/rxswift_core/observable/driver.md)
* [map](/rxswift/decision_tree/map.md)
* [共享附加作用](/rxswift/recipes/share_side_effects.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://3440217568.gitbook.io/rxswift/rxswift_core/observable/signal.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
