Swift 中的嵌套间接枚举
Nested indirect enums in Swift
我正在写一个 AudioManager in Swift 3(请帮我起一个比 "AudioManager" 更好的名字)来包装 AVPlayer
。目的是让播放器处理中断、路由更改并支持自定义播放速率、睡眠计时器、命令中心、正在播放信息等。由于 AVFoundation
大量 事件驱动 ,利用 KVO
和 NSNotification
让我的项目事件驱动也很有意义。我合并了一个消息系统,应用程序的不同部分将事件向上发送链,一直到根节点 AudioManager。所以我想要一个 enum
的事件表示,因为这是最有意义的。但是,我希望我的事件按例如分组RouteChange、BufferingEvent、InterruptionEvent 等。所以我终于使用 nested 让它工作了枚举.
我正在编写一个示例 GUI,然后它可以 调入 来自 AudioManager 的事件,而不必使用 NSNotification
,或 闭包。
EDITTED 使用@andyvn22
提供的答案
enum AudioError: Error {
indirect case buffering(Buffering)
enum Buffering {
case unknown
}
indirect case playback(Playback)
enum Playback {
case failedToSetupAVAsset
case failedToSetupAVItem
}
init(_ buffering: Buffering) {
self = .buffering(buffering)
}
init(_ playback: Playback) {
self = .playback(playback)
}
}
enum Event {
case failure(AudioError)
init(_ error: AudioError) {
self = .failure(error)
}
init(_ bufferingError: AudioError.Buffering) {
self = .failure(AudioError.buffering(bufferingError))
}
init(_ playbackError: AudioError.Playback) {
self = .failure(AudioError.playback(playbackError))
}
indirect case buffering(Buffering)
enum Buffering {
case idle, started, finished
}
indirect case playback(Playback)
enum Playback {
case tick, wasPaused
}
indirect case route(RouteChange)
enum RouteChange {
case unavailable, available
}
indirect case interruption(Interruption)
enum Interruption {
case interrupted, interruptionEnded
}
}
您可以将所有内容粘贴到 Swift Playground,然后添加 handle
方法并使用下面的调用示例调用它:
func handle(_ error: AudioError.Buffering) {
handle(AudioError.buffering(error))
}
func handle(_ error: AudioError) {
handle(Event.failure(error))
}
func handle(_ event: Event) {
switch event {
case .failure(let errorType):
print("failure", terminator: " ")
switch errorType {
case .playback(let error):
print("playback", terminator: " ")
switch error {
case .failedToSetupAVAsset:
print("setupAVAsset")
case .failedToSetupAVItem:
print("setupAVItem")
}
case .buffering(let error):
print("buffering", terminator: " ")
switch error {
case .unknown:
print("unknown")
}
}
case .buffering(let buffering):
print("buffering", terminator: " ")
switch buffering {
case .idle:
print("idle")
case .started:
print("started")
case .finished:
print("finished")
}
case .playback(let playback):
print("playback", terminator: " ")
switch playback {
case .tick:
print("tick")
case .wasPaused:
print("wasPaused")
}
default:
print("unhandled case")
}
}
/* All these are equivalent */
handle(Event.failure(.buffering(.unknown)))
handle(Event(.buffering(.unknown)))
handle(Event(AudioError(.unknown)))
handle(Event(.unknown))
handle(.unknown)
原始问题
然而,写 handle(Event(.buffering(.unknown)))
有点乏味,它已经是 handle(Event.failure(.buffering(.unknown)))
的简写版本。
我的问题:
是否可以仅使用 AudioError.Buffering 或 AudioError.Playback 中的内壳来创建带有 case .failure
的 Event
?
允许做这样的事情:
handle(Event(.unknown))
假设 AudioError.Buffering 和 AudioError.Playback 不共享同名案例...
也许我错过了一些很棒的部分 Swift 3 什么允许这样做?
是——通过重载初始化器,您可以允许任何子类型进行初始化。例如:
enum AudioError: Error {
indirect case buffering(Buffering)
enum Buffering {
case unknown
}
indirect case playback(Playback)
enum Playback {
case failedToSetupAVAsset
case failedToSetupAVItem
}
init(_ buffering: Buffering) {
self = .buffering(buffering)
}
init(_ playback: Playback) {
self = .playback(playback)
}
}
let example = AudioError(.failedToSetupAVAsset) //this works...
let other = AudioError(.unknown) //but so does this.
通过为每个子类型创建许多类似这样的初始值设定项,但在 Event
而不是 AudioError
上,您可以根据需要嵌套任意数量,而不会使语法复杂化。
我正在写一个 AudioManager in Swift 3(请帮我起一个比 "AudioManager" 更好的名字)来包装 AVPlayer
。目的是让播放器处理中断、路由更改并支持自定义播放速率、睡眠计时器、命令中心、正在播放信息等。由于 AVFoundation
大量 事件驱动 ,利用 KVO
和 NSNotification
让我的项目事件驱动也很有意义。我合并了一个消息系统,应用程序的不同部分将事件向上发送链,一直到根节点 AudioManager。所以我想要一个 enum
的事件表示,因为这是最有意义的。但是,我希望我的事件按例如分组RouteChange、BufferingEvent、InterruptionEvent 等。所以我终于使用 nested 让它工作了枚举.
我正在编写一个示例 GUI,然后它可以 调入 来自 AudioManager 的事件,而不必使用 NSNotification
,或 闭包。
EDITTED 使用@andyvn22
提供的答案enum AudioError: Error {
indirect case buffering(Buffering)
enum Buffering {
case unknown
}
indirect case playback(Playback)
enum Playback {
case failedToSetupAVAsset
case failedToSetupAVItem
}
init(_ buffering: Buffering) {
self = .buffering(buffering)
}
init(_ playback: Playback) {
self = .playback(playback)
}
}
enum Event {
case failure(AudioError)
init(_ error: AudioError) {
self = .failure(error)
}
init(_ bufferingError: AudioError.Buffering) {
self = .failure(AudioError.buffering(bufferingError))
}
init(_ playbackError: AudioError.Playback) {
self = .failure(AudioError.playback(playbackError))
}
indirect case buffering(Buffering)
enum Buffering {
case idle, started, finished
}
indirect case playback(Playback)
enum Playback {
case tick, wasPaused
}
indirect case route(RouteChange)
enum RouteChange {
case unavailable, available
}
indirect case interruption(Interruption)
enum Interruption {
case interrupted, interruptionEnded
}
}
您可以将所有内容粘贴到 Swift Playground,然后添加 handle
方法并使用下面的调用示例调用它:
func handle(_ error: AudioError.Buffering) {
handle(AudioError.buffering(error))
}
func handle(_ error: AudioError) {
handle(Event.failure(error))
}
func handle(_ event: Event) {
switch event {
case .failure(let errorType):
print("failure", terminator: " ")
switch errorType {
case .playback(let error):
print("playback", terminator: " ")
switch error {
case .failedToSetupAVAsset:
print("setupAVAsset")
case .failedToSetupAVItem:
print("setupAVItem")
}
case .buffering(let error):
print("buffering", terminator: " ")
switch error {
case .unknown:
print("unknown")
}
}
case .buffering(let buffering):
print("buffering", terminator: " ")
switch buffering {
case .idle:
print("idle")
case .started:
print("started")
case .finished:
print("finished")
}
case .playback(let playback):
print("playback", terminator: " ")
switch playback {
case .tick:
print("tick")
case .wasPaused:
print("wasPaused")
}
default:
print("unhandled case")
}
}
/* All these are equivalent */
handle(Event.failure(.buffering(.unknown)))
handle(Event(.buffering(.unknown)))
handle(Event(AudioError(.unknown)))
handle(Event(.unknown))
handle(.unknown)
原始问题
然而,写 handle(Event(.buffering(.unknown)))
有点乏味,它已经是 handle(Event.failure(.buffering(.unknown)))
的简写版本。
我的问题:
是否可以仅使用 AudioError.Buffering 或 AudioError.Playback 中的内壳来创建带有 case .failure
的 Event
?
允许做这样的事情:
handle(Event(.unknown))
假设 AudioError.Buffering 和 AudioError.Playback 不共享同名案例...
也许我错过了一些很棒的部分 Swift 3 什么允许这样做?
是——通过重载初始化器,您可以允许任何子类型进行初始化。例如:
enum AudioError: Error {
indirect case buffering(Buffering)
enum Buffering {
case unknown
}
indirect case playback(Playback)
enum Playback {
case failedToSetupAVAsset
case failedToSetupAVItem
}
init(_ buffering: Buffering) {
self = .buffering(buffering)
}
init(_ playback: Playback) {
self = .playback(playback)
}
}
let example = AudioError(.failedToSetupAVAsset) //this works...
let other = AudioError(.unknown) //but so does this.
通过为每个子类型创建许多类似这样的初始值设定项,但在 Event
而不是 AudioError
上,您可以根据需要嵌套任意数量,而不会使语法复杂化。