SwiftEvents 2.1.2

SwiftEvents 2.1.2

Denis Simon 维护。



  • Denis Simon

SwiftEvents

Swift Platform

SwiftEvents 是一个轻量级的库,用于创建和观察事件。

它包括

  • Observable<T>,它可以用于 MVVM 中的数据绑定,并使用 Event 类实现。
  • Event<T>,用于基于闭包的代理和一对一的刷新通知。

特点

  • 类型安全:具体类型值直接传递给订阅者,无需向下转型

  • 线程安全:您可以从任何线程调用 subscribe / bindtriggerunsubscribe / 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 拖入项目树。

用法

数据绑定

  1. 将观察的属性的 Type 替换为 Observable<Type>
  2. 绑定到 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 可以有多个观察者。

代理

代理可以根据协议或基于闭包实现。这种一对一的连接可以分两步完成

  1. 为发布者创建 Event
  2. 订阅到 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)
    }
}

别名方法

对于 addSubscriberremoveSubscriberremoveAllSubscribers 事件,存在别名方法,它们分别与 subscribeunsubscribeunsubscribeAll 的功能相同。

许可证

MIT 许可证 下授权