⚠️已弃用且不再维护⚠️

iOS 13 和 Apple 的其他 2019 年操作系统包含了新的 Combine 事件处理框架。我已经将我自己的应用 Day Planner 迁移到使用 Combine 而不是 TinyEvents,因此我计划不再对此库进行任何更新,并鼓励您在可能的情况下也迁移到 Combine。迁移过程非常简单方便,因为 Combine 的 PassthroughSubject<Void, Never> 几乎可以作为 TinyEvent 的直接替代品(并使用 PassthroughSubject<T, Never> 作为 TinyEventWithData<T> 的替代品)。

TinyEvents

一个用于 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 itVariable 'someObserver' was written to, but never read 的警告?

您是否将观察者存储在局部变量或常量中,而不是属性中? 这没关系,但这些警告暗示了一些重要的事情,即 自动引用计数系统会将未使用的局部对象视为不必要的,并可以立即销毁它们,并且如果观察者被销毁,您的闭包将不会被调用。 解决此问题的方法是使用 Swift 标准库函数 withExtendedLifetime(_:_:) 显式地告诉系统您希望观察者保持活动状态

let event = TinyEvent()
let observer = event.add {
    // […]
}
withExtendedLifetime(observer) {
    event.fire()
}

以我的经验,这在正常使用中并不常见(即使有),因为拥有一个像函数调用一样短暂的事件观察者是不寻常的,但这种习惯用法在 TinyEvent 测试中被广泛使用。