SwiftySignals 3.0.5

SwiftySignals 3.0.5

测试已测试
语言语言 SwiftSwift
许可 MIT
发布最后发布2017年3月
SwiftSwift 版本3.0
SPM支持 SPM

Patrick Sturm 维护。



SwiftySignals (草案)

作者

Patrick Sturm, [email protected]

许可

SwiftySignals 可在 MIT 许可证下使用。更多信息请参阅 LICENSE 文件。

简介

SwiftySignals 最初是一个包含几个类的简单框架。在 SwiftySignals 2 中,并发完全被忽略,留由用户处理。从 SwiftySignals 3 开始,API 变得更加灵活和线程安全。并发得到了广泛支持。SwiftySignals 3 现在实现了观察者模式,并基于 Apple 的调度框架。

基本概念

SwiftySignals 的基本概念是可观察对象和观察者。可观察对象能够发送消息,而观察者能够接收并处理消息。一般来说,您无需自己定义可观察对象或观察者。您只需处理辅助类。SwiftySignals 中主要有两种辅助类:

  1. 消息源
  2. 修改器

消息源包含一个或多个可观察对象。修改器既是观察者又是可观察对象。可以连接修改器到一个可观察对象。修改器能够过滤、映射、丢弃和生成消息。由于修改器本身就是可观察对象,因此可以将修改器连接到修改器链。消息从消息源开始,沿着修改器链发送。

Signal<T> 是消息源的最简单实现。信号可以用于发送类型为 T 的消息。要这样做,可以使用函数 Signal<T>.fire(with: T)。如果引发一个消息,则将其发送到连接到 Signal<T>.fired 的所有修改器,这被称为终点。

连接修改器到信号相当简单。假设,我们想在消息引发时打印消息。为此,我们可以使用修改器 then 连接到信号的终点 fired

let signal = Signal<Int>(value: 15)
let observables = ObservableCollection()
signal
    .fired
    .then { print($0) }
    .append(to: observables)
signal.fire(with: 20)

需要注意的是,必须将修改器链存储在某个位置。如果不这样做,则由于自动引用计数,修改器链将立即被删除。然而,可以附录到可观察集合中的修改器以使它们保持活动状态。在这种情况下,修改器链将与可观察集合一起被销毁。

可用的消息来源

在SwiftySignals中定义了一些消息来源。

信号

信号属于Signal<T>类。信号有一个函数fire(with message: T),它将消息发送到所有连接到信号端点fired的可观察对象。

属性

属性属于Property<T>类。属性有一个类型为T的属性value。每当值被修改时,新值都会被发送到属性的端点didSet。属性是线程安全的。这意味着可以从所有线程中读取和写入属性的值。但请注意,读取是一个阻塞命令,可能会在某些情况下造成问题。

let property = Property<Int>(value: 0)
let observables = ObservableCollection()

property
    .didSet
    .then { print("Value changed to \($0)") }
    .append(to: observables)

for i in 0..<10 {
    property.value += 1
}

计时器信号

计时器信号属于TimerSignal类。这样的计时器可以看作是带类型Void的消息的时间触发信号。计时器通过其init(repeats: Bool)函数配置,并通过fire激活。计时器以给定的时间间隔触发消息(如果repeats为true,则持续进行)。

let timer = TimerSignal(repeats: true)
let observables = ObservableCollection()
timer
    .fired
    .then {.print("Timer has been triggered") }
    .append(to: observables)

timer.fire(after: Measurement(value: 10, UnitDuration.seconds)

可用的修饰符

不同的修饰符可以连接到端点。修饰符将可观察对象转换为不同的可观察对象。由于修饰符也是可观察对象,因此可以将不同的修饰符连接在一起。如果连接了一个修饰符,它将自动接收最后发送的消息。

Then修饰符

.then函数将一个修饰符连接到其中,当发送类型为T的消息时执行操作。定义此类操作有两种方式:

  1. 通过带有函数.then(do: (T)->Void)的闭包
  2. 通过实例:.then(call: (Object)->((T)->Void)), on: Object) 消息经过操作处理后,会被发送到所有连接到修饰符的可观察对象。

    class ViewController { private let property = Property(value: 56) private let observables = ObservableCollection()

    override func viewDidLoad() {
        property
            .didSet
            .then(call: ViewController.update, on: self)
        property.value = 67
    }
    
    func update(value: Int) {
        print("Value = \(value)")
    }
    

    }

Filter修饰符

.filter(predicate: (T)->Bool)函数连接一个修饰符,检查消息是否满足给定的谓词。如果谓词返回值为true,则将消息发送到所有连接到修饰符的可观察对象。如果谓词返回值为false,则丢弃消息。

let property = Property(value: 45)
let observables = Observables()

property
    .didSet
    .filter { $0 >= 100 }
    .then { print("Value \($0) is larger or equal than 100") }
    .append(to: observables)

Map修饰符

.map(transform: (T)->S)函数连接一个修饰符,将传入的消息类型从T转换为S。转换后的消息被发送到所有连接到修饰符的可观察对象。

let property = Property(value: 100)
property
    .didSet
    .map { 2 * $0 }
    .then { print($0) }
    .append(to: observables)

Throttle修饰符

.throttle(pause: Measurement<UnitDuration>)函数连接一个修饰符,如果消息发送得太快,就会丢弃它们。需要在两个消息之间至少有一个定义的时间暂停,这样就不会丢失任何消息。

Discard修饰符

.discard(first n: Int)函数连接一个修饰符,丢弃前n个消息。在那之后的所有消息都会发送到连接到修饰符的可观察对象。

Distinct修饰符

函数.distinct()连接一个丢弃相等的前一条消息的修饰符。此修饰符仅适用于可比较的消息类型。

防抖修饰符

函数.debounce(timeout: Measurement)连接一个在给定时间(timeout)后发送消息的修饰符。如果在超时达到之前收到新消息,则重置倒计时。请注意,如果处理的消

并发

每个消息来源和修饰符都使用自己的分发队列进行同步。默认情况下,用户定义的闭包(例如在thenfiltermap中使用的闭包)将在主队列上执行。

  1. .dispatch(to queue: DispatchQueue)
  2. .dispatch(qos: DispatchQoS)

第一个版本将所有闭包委托给给定的队列。第二个版本将所有闭包委托给具有指定质量服务类的全局分发队列。

如果闭包应在修饰符的同步队列中执行,则可以使用.noDispatch()函数。

let property = Property(value: 50)
let observables = Observables()

property
    .didSet
    .dispatch(qos: DispatchQoS.userInitiated)
    .then { print("I am running on a global queue.") }
    .dispatch(qos: DispatchQoS.main)
    .then { print("I am running on the main queue.") }
    .append(to: observables)