我想知道什麼是最佳實踐,當我需要一些函數公開和一些內部使用協議時。
我正在寫一個AudioManager在Swift 3包裝AVPlayer
作爲一個框架。
我想要一些方法是公開的,例如使用AudioManager的ViewController可以訪問某些方法,但某些方法不會暴露在框架
- >即訪問修飾符internal
而不是public
之外。
我正在用協議驅動設計編寫框架,幾乎每個部分都應該有一個協議。
因此協議正在與框架內的協議交談。
例如主類 - AudioManager
- 具有AudioPlayer
,並且應該能夠調用其上的一些internal
函數,例如
。 pause(reason:)
但該方法應該是internal
而不是暴露在框架之外。
這裏是一個例子。具有內部函數和屬性的Swift公共協議
internal enum PauseReason {
case byUser
case routeChange
}
// Compilation error: `Public protocol cannot refine an internal protocol`
public protocol AudioPlayerProtocol: InternalAudioPlayerProtocol {
func pause() // I want
}
internal protocol InternalAudioPlayerProtocol {
func pause(reason: PauseReason) // Should only be accessible within the framework
}
public class AudioPlayer: AudioPlayerProtocol {
public func pause() {
pause(reason: .byUser)
}
// This would probably not compile because it is inside a public class...
internal func pause(reason: PauseReason) { //I want this to be internal
// save reason and to stuff with it later on
}
}
public protocol AudioManagerProtocol {
var audioPlayer: AudioPlayerProtocol { get }
}
public class AudioManager: AudioManagerProtocol {
public let audioPlayer: AudioPlayerProtocol
init() {
audioPlayer = AudioPlayer()
NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange(_:)), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil)
}
func handleRouteChange(_ notification: Notification) {
guard
let userInfo = notification.userInfo,
let reasonRaw = userInfo[AVAudioSessionRouteChangeReasonKey] as? NSNumber,
let reason = AVAudioSessionRouteChangeReason(rawValue: reasonRaw.uintValue)
else { print("what could not get route change") }
switch reason {
case .oldDeviceUnavailable:
pauseBecauseOfRouteChange()
default:
break
}
}
}
private extension AudioManager {
func pauseBecauseOfRouteChange() {
audioPlayer.pause(reason: .routeChange)
}
}
// Outside of Audio framework
class PlayerViewController: UIViewController {
fileprivate let audioManager: AudioManagerProtocol
@IBAction didPressPauseButton(_ sender: UIButton) {
// I want the `user of the Audio framwwork` (in this case a ViewController)
// to only be able to `see` `pause()` and not `pause(reason:)`
audioManager.audioPlayer.pause()
}
}
我知道我可以得到它通過改變方法pauseBecauseOfRouteChange
工作看起來像這樣:
func pauseBecauseOfRouteChange() {
guard let internalPlayer = audioPlayer as? InternalAudioPlayerProtocol else { return }
internalPlayer.pause(reason: .routeChange)
}
但我想知道如果有一個更好的解決方案?
類似於標記AudioPlayerProtocol
細化了InternalAudioPlayerProtocol
...
或者你們是如何做到這一點的?
如果該框架不公開用於內部使用的方法和變量,則該框架更美觀!
謝謝!