信号
信号是一个创建和观察事件的库。它用更强大、更优雅的东西取代了代理、操作和NSNotificationCenter。
特点
- 附加并忘记观察
- 类型安全
- 过滤观察
- 延迟和队列观察
- 全面的单元测试覆盖
要求
- iOS 7.0 / watchOS 2.0 / Mac OS X 10.9
- Swift 4.2
安装
要将信号与针对iOS 7的目标项目一起使用,只需将Signals.swift
复制到您的项目中。
CocoaPods
要将 Signals 集成到您的项目中,请将以下内容添加到您的 Podfile
platform :ios, '8.0'
use_frameworks!
pod 'Signals', '~> 6.0'
Carthage
使用 Carthage 将 Signals 集成到您的项目中,请将以下内容添加到您的 Cartfile
github "artman/Signals" ~> 6.0
Swift Package Manager
使用 SwiftPM 将 Signals 集成到您的项目中,请将以下内容添加到您的 Package.swift
dependencies: [
.package(url: "https://github.com/artman/Signals", from: "6.0.0"),
],
快速入门
通过创建一个或多个信号,使类的事件可观察
class NetworkLoader {
// Creates a number of signals that can be subscribed to
let onData = Signal<(data:NSData, error:NSError)>()
let onProgress = Signal<Float>()
...
func receivedData(receivedData:NSData, receivedError:NSError) {
// Whenever appropriate, fire off any of the signals
self.onProgress.fire(1.0)
self.onData.fire((data:receivedData, error:receivedError))
}
}
从应用程序的其它地方订阅这些信号
let networkLoader = NetworkLoader("http://artman.fi")
networkLoader.onProgress.subscribe(with: self) { (progress) in
print("Loading progress: \(progress*100)%")
}
networkLoader.onData.subscribe(with: self) { (data, error) in
// Do something with the data
}
向 Signals 添加订阅是一个附件和忘记的操作。如果订阅的对象被释放,Signal
会取消订阅,所以您不需要显式管理您订阅的取消。
信号不受限于一个订阅者。多个对象可以订阅同一个信号。
您还可以在事件发生后订阅这些事件
networkLoader.onProgress.subscribePast(with: self) { (progress) in
// This will immediately fire with last progress that was reported
// by the onProgress signal
println("Loading progress: \(progress*100)%")
}
高级主题
信号订阅可以应用过滤器
networkLoader.onProgress.subscribe(with: self) { (progress) in
// This fires when progress is done
}.filter { $0 == 1.0 }
您可以通过抽样来降低订阅执行频率,而不管 Signal
多么频繁地触发
networkLoader.onProgress.subscribe(with: self) { (progress) in
// Executed once per second while progress changes
}.sample(every: 1.0)
默认情况下,订阅会在触发 Signal
的线程上同步执行。要更改默认行为,您可以使用 dispatchOnQueue
方法来定义分发队列
networkLoader.onProgress.subscribe(with: self) { (progress) in
// This fires on the main queue
}.dispatchOnQueue(DispatchQueue.main)
如果您不喜欢在触发包含元组的信号时使用的双引号,可以使用自定义的 =>
操作符来触发数据
// If you don't like the double quotes when firing signals that have tuples
self.onData.fire((data:receivedData, error:receivedError))
// You can use the => operator to fire the signal
self.onData => (data:receivedData, error:receivedError)
// Also works for signals without tuples
self.onProgress => 1.0
替换动作
信号扩展了所有从UIControl派生的类(不在OS X上可用),并允许您使用信号来监听控件事件,提高代码的局部性。
let button = UIButton()
button.onTouchUpInside.observe(with: self) {
// Handle the touch
}
let slider = UISlider()
slider.onValueChanged.observe(with: self) {
// Handle value change
}
替换代理
信号简单且现代,大大减少了设置委托所需的样板代码。
您更愿意使用代理实现回调吗?
- 创建一个用于定义委托的协议
- 在希望提供委托的类上创建一个委托属性
- 标记所有想要成为代理的类以遵守代理协议
- 在想要成为代理的类上实现委托方法
- 设置委托属性以将实例成为代理
- 在调用它之前检查您的代理是否实现了每个委托方法
或者用信号做同样的事情
- 为想要提供事件的类创建一个信号
- 订阅信号
替换NotificationCenter
随着工程师团队的壮大,NotificationCenter很快就会变成一个反模式。具有隐式数据且无编译器保护的全球通知很容易使您的代码出错,难以维护和重构。
用信号替换NotificationCenter将为您提供由编译器强制执行的类型安全性,这有助于您在快速移动时维护代码。
通信
- 如果您发现了一个错误,请打开一个问题或通过拉取请求提交修复。
- 如果您有功能请求,请打开一个问题或通过拉取请求提交实现,或者通过Twitter联系我 @artman
- 如果您希望贡献,请在主分支上提交一个拉取请求。
许可协议
Signals 在MIT许可下发布。有关更多信息,请参阅LICENSE文件。