iOS 13 和 Apple 的其他 2019 年操作系统包含了新的 Combine 事件处理框架。我已经将我自己的应用 Day Planner 迁移到使用 Combine 而不是 TinyEvents,因此我计划不再对此库进行任何更新,并鼓励您在可能的情况下也迁移到 Combine。迁移过程非常简单方便,因为 Combine 的 PassthroughSubject<Void, Never>
几乎可以作为 TinyEvent
的直接替代品(并使用 PassthroughSubject<T, Never>
作为 TinyEventWithData<T>
的替代品)。
一个用于 Swift 的微型事件系统(1 个源文件,113 行代码)
import TinyEvents
创建一个事件并添加一个闭包,以便在事件触发时调用
event = TinyEvent()
observer = event.add { print("Event fired") }
然后在稍后触发它
event.fire()
要移除观察者,只需销毁它。可以显式地销毁
observer = nil
或者,如果观察者作为您某个对象的属性存储,则当您的对象被销毁时,它将自动被移除
class SomeViewController: UIViewController {
// […]
override func viewDidLoad() {
// […]
observer = someSystem.importantEvent.add { [unowned self] in
self.importantEventLabel.isHidden = false
}
}
var observer: TinyEventObserver? // I'll be destroyed automatically with the view controller.
}
您可以使用 TinyEventWithData<T>
而不是 TinyEvent
来向观察者传递数据
enum Option { case good, better, best }
userSelectedOption = TinyEventWithData<Option>()
// The observers will be of type `TinyEventWithDataObserver<Option>`
optionObserver = userSelectedOption.add { selectedOption in
print(selectedOption)
}
userSelectedOption.fire(Option.best)
使用元组(或结构体或任何其他类型的结构)传递多条数据
titleRatedByUser = TinyEventWithData<(String, Int)>()
observer = titleRatedByUser.add { title, rating in
print("\(title) rated: \(rating)")
}
titleRatedByUser.fire(("Foo", 10))
简而言之,每当您在闭包中引用 self
并在同一对象上存储观察者时,您应该在闭包的捕获列表中使用 [unowned self]
以避免创建引用循环(有关示例,请参见上面的 SomeViewController
列表)。
这很重要,因为如果您不添加 [unowned self]
,那么您将创建一个引用循环——在本例中是 view controller -> observer -> closure -> view controller
——然后即使视图控制器通常会被销毁和释放,它也会因闭包中的引用而保持活动状态,从而导致内存泄漏。
如果您想了解更多关于此主题的信息,请参阅 《Swift 编程语言》的自动引用计数章节。
您可以使用 Swift Package Manager(或 Xcode 与 Swift Package Manager 的集成)将 TinyEvents 添加到您的项目中,方法是将此仓库添加到您的依赖项中,或者您可以直接将 TinyEvents.swift
文件拖放到您的项目中。
Immutable value 'someObserver' was never used; consider replacing with '_' or removing it
或 Variable 'someObserver' was written to, but never read
的警告?您是否将观察者存储在局部变量或常量中,而不是属性中? 这没关系,但这些警告暗示了一些重要的事情,即 自动引用计数系统会将未使用的局部对象视为不必要的,并可以立即销毁它们,并且如果观察者被销毁,您的闭包将不会被调用。 解决此问题的方法是使用 Swift 标准库函数 withExtendedLifetime(_:_:)
显式地告诉系统您希望观察者保持活动状态
let event = TinyEvent()
let observer = event.add {
// […]
}
withExtendedLifetime(observer) {
event.fire()
}
以我的经验,这在正常使用中并不常见(即使有),因为拥有一个像函数调用一样短暂的事件观察者是不寻常的,但这种习惯用法在 TinyEvent 测试中被广泛使用。