Swift中的嵌套间接枚举

时间:2016-09-15 19:38:58

标签: ios swift enums avplayer swift3

我正在撰写一个AudioManager in Swift 3(请帮助我提供一个比“AudioManager”更好的名字)来包裹AVPlayer。目的是让玩家处理中断,路由更改并支持自定义播放速率,睡眠定时器,命令中心,现在播放信息等。由于AVFoundation严重事件驱动,使用KVONSNotification我的项目活动也是有意义的。我已经整合了一个消息传递系统,应用程序的不同部分将链上的事件发送到根节点 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的一些很酷的部分会允许这样做吗?

1 个答案:

答案 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上,您可以尽可能地嵌套,而不会使语法复杂化。