SwiftEvents
SwiftEvents 是一个轻量级的库,用于创建和观察事件。
它包括
Observable<T>
,它可以用于 MVVM 中的数据绑定,并使用 Event 类实现。Event<T>
,用于基于闭包的代理和一对一的刷新通知。
特点
-
类型安全:具体类型值直接传递给订阅者,无需向下转型
-
线程安全:您可以从任何线程调用
subscribe
/bind
,trigger
,unsubscribe
/unbind
而不会出现数据竞争等问题 -
内存安全:自动防止保留循环,不需要在订阅/绑定时严格指定
[weak self]
。无论您是否指定了[weak self]
,有时会忘记指定 - 以确保对内存泄露的安全性。同样,当订阅者/观察者被销毁时,它们将被自动删除 -
全面的单元测试覆盖。
安装
CocoaPods
要使用 CocoaPods 安装 SwiftEvents,请将此行添加到您的 Podfile
中
pod 'SwiftEvents', '~> 1.1.2'
Carthage
要使用 Carthage 安装 SwiftEvents,请将此行添加到您的 Cartfile
中
github "denissimon/SwiftEvents"
Swift 包管理器
要使用 Swift 包管理器 安装 SwiftEvents,请将其添加到您的 Package.swift
文件中
dependencies: [
.Package(url: "https://github.com/denissimon/SwiftEvents.git", from: "1.1.2")
]
手动
只需将 SwiftEvents.swift
拖入项目树。
用法
数据绑定
- 将观察的属性的
Type
替换为Observable<Type>
- 绑定到 Observable
示例
class ViewModel {
var infoLabel: Observable<String> = Observable("init value")
func set(newValue: String) {
infoLabel.value = newValue
}
}
class View: UIViewController {
var viewModel = ViewModel()
@IBOutlet weak var infoLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
infoLabel.text = viewModel.infoLabel.value
viewModel.infoLabel.bind(self) { (self, value) in self.updateInfoLabel(value) }
}
private func updateInfoLabel(_ value: String) {
infoLabel.text = value
}
}
注意:在此示例中,故意没有在 (self, value)
之前的闭包中指定捕获列表,因为 SwiftEvents 将在底层构建一个新的闭包,其中包含 [weak target]
。这样就可以避免强引用周期。
在上面的示例中,每当 ViewModel 更改了 observable 属性 infoLabel
的值时,View 都会收到通知并更新 infoLabel.text
。
您可以使用中缀运算符 <<<< 为 observable 属性设置新值
infoLabel <<< newValue
与 Event 一样,Observable 可以有多个观察者。
代理
代理可以根据协议或基于闭包实现。这种一对一的连接可以分两步完成
- 为发布者创建 Event
- 订阅到 Event
示例
class MyModel {
let didDownload = Event<UIImage?>()
func downloadImage(for url: URL) {
service.download(url: url) { [weak self] image in
self?.didDownload.trigger(image)
}
}
}
class MyViewController: UIViewController {
let model = MyModel()
var image: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
model.didDownload.subscribe(self) { (self, image) in self.updateImage(image) }
}
private func updateImage(_ image: UIImage?) {
self.image = image
}
}
您可以使用 Event 与任何复杂类型一起使用,包括自定义类型和多值类型如 (UIImage, Int)
。您还可以创建几个事件(如 didDownload、onNetworkError 等),并且仅触发所需的。
通知
如果通知必须是多对一,或者需要连接的两个对象间隔太远,可以使用 SwiftEvents 如同 NotificationCenter。
示例
public class EventService {
public static let get = EventService()
private init() {}
public let onDataUpdate = Event<String?>()
}
class Controller1 {
init() {
EventService.get.onDataUpdate.subscribe(self) { (self, data) in
print("Controller1: '\(data)'")
}
}
}
class Controller2 {
init() {
EventService.get.onDataUpdate.subscribe(self) { (self, data) in
print("Controller2: '\(data)'")
}
}
}
class DataModel {
func requestData() {
// requesting code goes here
data = "some data"
EventService.get.onDataUpdate.trigger(data)
}
}
let sub1 = Controller1()
let sub2 = Controller2()
let pub = DataModel()
pub.requestData()
// => Controller1: 'some data'
// => Controller2: 'some data'
更多示例
更多用法示例可以在这个 演示应用 中找到。
高级特性
手动移除订阅者/观察者
someEvent.subscribe(self) { (self, value) in self.setValue(value) }
someEvent.unsubscribe(self)
someObservable.bind(self) { (self, value) in self.setValue(value) }
someObservable.unbind(self)
移除所有订阅者/观察者
someEvent.unsubscribeAll()
someObservable.unbindAll()
事件的订阅者数量
let subscribersCount = someEvent.subscribersCount
事件触发次数
let triggersCount = someEvent.triggersCount
重置触发次数计数器
someEvent.resetTriggersCount()
队列: 메인 스레드dispatcher
默认情况下,提供的事件处理程序在触发事件的线程上执行。要更改此默认行为,您可以在订阅/绑定时设置此参数。
// This executes the handler on the main queue
someEvent.subscribe(self, queue: .main) { (self, image) in self.updateImage(image) }
someObservable.bind(self, queue: .main) { (self, image) in self.updateImage(image) }
一次性通知
确保处理程序只执行一次
someObservable.bind(self) { (self, data) in
self.useData(data)
self.someObservable.unbind(self)
}
n 次通知
确保处理程序最多执行 n
次
someEvent.subscribe(self) { (self, data) in
self.useData(data)
if self.someEvent.triggersCount == n {
self.someEvent.unsubscribe(self)
}
}
别名方法
对于 addSubscriber
、removeSubscriber
和 removeAllSubscribers
事件,存在别名方法,它们分别与 subscribe
、unsubscribe
和 unsubscribeAll
的功能相同。
许可证
在 MIT 许可证 下授权