测试已测试 | ✓ |
Lang语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2017 年 12 月 |
SwiftSwift 版本 | 4.0 |
SPM支持 SPM | ✗ |
由 Rui Peres 维护。
作为自身是一位 ReactiveSwift 用户,很多时候,很难说服别人开始使用它。不管好还是坏,大多数项目/团队可能还没有准备好采用它
尽管如此,一个宝贵的模式仍然可以用,即使没有这样一个如此棒的库,如 ReactiveSwift。
Receiver
!Receiver
仅仅是一个意见领袖的微框架实现 观察者模式 (~120 行代码)。或者,如果您更喜欢的话,没有 F
和一个非常小的 R
的 FRP
(rP)
如果您使用 Carthage 管理依赖项,只需将 Receiver 添加到您的 Cartfile
github "RuiAAPeres/Receiver" ~> 0.0.1
如果您使用 Carthage 构建依赖项,请确保您已经将 Receiver.framework
添加到目标 "链接框架和库" 部分,并在 Carthage 框架复制构建阶段中包含它们。
如果您使用 CocoaPods 管理依赖项,只需在您的 Podfile 中添加 Receiver
pod 'Receiver', '~> 0.0.1'
让我们从基础知识开始。总共 有三个方法。没错。
let (transmitter, receiver) = Receiver<Int>.make()
一个 receiver
没有一个关联的 transmitter
无法创建(那会是什么样子?)
这就是您如何观察事件
receiver.listen { cheezburgers in print("Can I haz \(cheezburgers) cheezburger. 🐈") }
如预期的那样,您可以根据需要多次这样做
receiver.listen { cheezburgers in print("Can I haz \(cheezburgers) cheezburger. 🐈") }
receiver.listen { cheezburgers in print("I have \(cheezburgers) cheezburgers and you have none!")}
当事件被广播时,将调用两个处理程序。
这就是您发送事件的方式
transmitter.broadcast(1)
Receiver 提供了一组类似于 ReactiveSwift 的运算符
映射
过滤
带前一个
取
跳过
跳过重复项
跳过空值
如果您熟悉 FRP,您一定听说过 冷和热语义(即使没有也不必担心!)Receiver
提供了三种模式,在初始化时通过make(strategy:)
显式指定。默认情况下,Receiver
为.hot
。
.cold
let (transmitter, receiver) = Receiver<Int>.make(with: .cold)
transmitter.broadcast(1)
transmitter.broadcast(2)
transmitter.broadcast(3)
receiver.listen { wave in
// This will be called with `wave == 1`
// This will be called with `wave == 2`
// This will be called with `wave == 3`
// This will be called with `wave == 4`
}
transmitter.broadcast(4)
内部,Receiver
会保留之前发送的值的缓存。一旦有新的监听者接入,所有之前的值都会发送。当4
被发送时,它将按预期被“监听”。
.warm(upTo: Int)
这种策略允许你指定缓冲区的大小
let (transmitter, receiver) = Receiver<Int>.make(with: .warm(upTo: 1))
transmitter.broadcast(1)
transmitter.broadcast(2)
receiver.listen { wave in
// This will be called with `wave == 2`
// This will be called with `wave == 3`
}
transmitter.broadcast(3)
在这种情况下,1
永远不会被调用,因为指定的限制(upTo: 1
)过低,所以只保留2
在缓存中。
.hot
let (transmitter, receiver) = Receiver<Int>.make(with: .hot) // this is the default strategy
transmitter.broadcast(1)
transmitter.broadcast(2)
receiver.listen { wave in
// This will be called with `wave == 3`
}
transmitter.broadcast(3)
在监听之前广播的内容将被丢弃。
代码块中的make
方法遵循与ReactiveSwift中相同的处理方法,使用pipe
。由于receiver
只有和transmitter
一起才有意义,因此它们一起创建是合乎逻辑的。
许多库将读写者捆绑在同一个实体中。对于这个库的目的和使用案例,合理的做法是将这些关注点分离。这就像UITableView
和UITableViewDataSource
:一个供应另一个,因此将它们拆分成两个不同的实体可能更好。
当然,是为了让你的代码库变得非常棒。观察者模式可以在很多地方使用。在最简单的情况下,当委托不足以使用,并且存在1-to-N
的关系时。
跟踪UIApplication
的生命周期是这种用法的一个好例子
enum ApplicationLifecycle {
case didFinishLaunching
case didBecomeActive
case didEnterBackground
}
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
private var transmitter: Receiver<ApplicationLifecycle>.Transmitter!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let (transmitter, receiver) = Receiver<ApplicationLifecycle>.make()
self.transmitter = transmitter
// Pass down the `receiver` to where it's needed (e.g. ViewModel, Controllers)
transmitter.broadcast(.didFinishLaunching)
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
transmitter.broadcast(.didEnterBackground)
}
func applicationDidBecomeActive(_ application: UIApplication) {
transmitter.broadcast(.didBecomeActive)
}
}
类似地,同样的方法可以用于MVVM
class MyViewController: UIViewController {
private let viewModel: MyViewModel
private let transmitter: Receiver<UIViewControllerLifecycle>.Transmitter
init(viewModel: MyViewModel, transmitter: Receiver<UIViewControllerLifecycle>.Transmitter) {
self.viewModel = viewModel
self.transmitter = transmitter
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewdDidLoad()
transmitter.broadcast(.viewDidLoad)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
transmitter.broadcast(.viewDidAppear)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
transmitter.broadcast(.viewDidDisappear)
}
}
好处在于UIViewController
永远不需要知道receiver
的存在,就像它应该的那样。
在初始化时
let (transmitter, receiver) = Receiver<UIViewControllerLifecycle>.make()
let viewModel = MyViewModel(with: receiver)
let viewController = MyViewController(viewModel: viewModel, transmitter: transmitter)