我正在撰写一个AudioManager in Swift 3(请帮助我提供一个比“AudioManager”更好的名字)来包裹AVPlayer
。目的是让玩家处理中断,路由更改并支持自定义播放速率,睡眠定时器,命令中心,现在播放信息等。由于AVFoundation
严重事件驱动,使用KVO
和NSNotification
我的项目活动也是有意义的。我已经整合了一个消息传递系统,应用程序的不同部分将链上的事件发送到根节点 AudioManager 。所以我想要一个事件表示为enum
,因为这是最有意义的。但是,我希望我的事件按例如分组。 RouteChange , BufferingEvent , InterruptionEvent 等等。所以我终于使用嵌套枚举进行了工作。
我正在编写一个示例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 中的内部案例创建Event
case .failure
?< /强>
允许做这样的事情:
handle(Event(.unknown))
假设 AudioError.Buffering 和 AudioError.Playback 不共享具有相同名称的案例......
也许我已经错过了Swift 3的一些很酷的部分会允许这样做吗?
答案 0 :(得分:1)
是 - 通过重载初始化程序,您可以允许通过任何子类型进行初始化。例如:
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
上,您可以尽可能地嵌套,而不会使语法复杂化。