publicprotocolZPSettable: ZPObservable, ZPSessionSettable, ZPRemoteControlSettable, ZPCacheSettable { var url: URLConvertible { get } // 主要为初始化工程内部使用 var maxRetryCount: Int { getnonmutatingset } var progressInterval: TimeInterval { getnonmutatingset } }
为了能在使用侧支持链式调用,还需要对协议进行一些扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
extensionZPSettable { /// Maximum retry time when an error occurred. The default value is 1. publicfuncmaxRetryCount(_maxRetryCount: Int) -> Self { self.maxRetryCount = maxRetryCount returnself }
/// The time interval for playback progress callback. The default value is 1. publicfuncprogressInterval(_progressInterval: TimeInterval) -> Self { self.progressInterval = progressInterval returnself } }
publicprotocolZPObservable { var callbackQueue: DispatchQueue { getnonmutatingset }
var waitToPlay: ZPDelegate<(ZonPlayable, ZPWaitingReason), Void>? { getnonmutatingset } var play: ZPDelegate<(ZonPlayable, Float), Void>? { getnonmutatingset } var pause: ZPDelegate<ZonPlayable, Void>? { getnonmutatingset } var finish: ZPDelegate<(ZonPlayable, URL), Void>? { getnonmutatingset } var error: ZPDelegate<(ZonPlayable, ZonPlayer.Error), Void>? { getnonmutatingset } var progress: ZPDelegate<(ZonPlayable, TimeInterval, TimeInterval), Void>? { getnonmutatingset } var duration: ZPDelegate<(ZonPlayable, TimeInterval), Void>? { getnonmutatingset } var background: ZPDelegate<(ZonPlayable, Bool), Void>? { getnonmutatingset } var rate: ZPDelegate<(ZonPlayable, Float, Float), Void>? { getnonmutatingset } }
// 链式调用扩展 extensionZPObservable { /// Which dispatch queue to callback, the default value is main queue. publicfunccallbackQueue(_queue: DispatchQueue) -> Self { self.callbackQueue = queue returnself } // ...... }
publicprotocolZPSessionSettable { var session: ZPSessionable? { getnonmutatingset } }
/// The command of remote control. publicprotocolZPRemoteCommandable { funcenable() funcdisable() }
/// The remote control for player in lock screen or control center. /// /// - Important: The time for playback is rounded. publicprotocolZPRemoteControllable { var commands: [ZPRemoteCommandable] { getnonmutatingset }
var title: String? { getnonmutatingset } var artist: String? { getnonmutatingset } var artwork: UIImage? { getnonmutatingset }
var extraInfo: [String: Any]? { getnonmutatingset } }
/// Take snapshot for video frame. /// - Parameters: /// - time: Specified time interval for video, will replace current time instead of nil. /// - completion: Callback with optional image in main queue. functakeSnapshot(attime: TimeInterval?, completion: @escaping (UIImage?) -> Void)
/// Let player can playback in background. /// - Important: You should set supported audio session at first. funcenableBackgroundPlayback() funcdisableBackgroundPlayback() funcsuspendPlayingInfo() funcresumePlayingInfo() }
publicprotocolZPGettable { var isPlaying: Bool { get }
/// The volume for player is greater than or equal to 0 and less than or equal to 1. var volume: Float { get } var rate: Float { get } var currentTime: TimeInterval { get } var duration: TimeInterval { get } var url: URL { get } }
总结
在面向协议编程的大前提下,我们先后定义了 ZonPlayer 一系列的接口协议。虽然 Swift Module 天生自带模块名为命名空间,但保险起见我们还是在协议面前加上了前缀,Apple 的风格亦是如此。虽然我个人更喜欢类型嵌套(后面会看到不少这样的使用),但无奈它不支持协议的定义。下篇文章我们将详细说明部分协议定义的用意,以及播放器实现过程中遇到的一些坑点,👋~