gpt4 book ai didi

ios - 具有内部函数和属性的 Swift 公共(public)协议(protocol)

转载 作者:IT王子 更新时间:2023-10-29 05:31:55 28 4
gpt4 key购买 nike

我想知道在使用协议(protocol)时,当我希望某些函数是公开的,而某些函数对我来说是内部函数时,最佳实践是什么。

我正在写一个 AudioManagerSwift 3 中,将 AVPlayer 包装为一个框架。

我希望一些方法是公开的,例如使用 AudioManager 的 ViewController 可以访问某些方法,但某些方法不会在框架之外公开
-> 即具有访问修饰符 internal 而不是 public.

我正在编写协议(protocol)驱动设计的框架,几乎每个部分都应该有一个协议(protocol)。
所以协议(protocol)正在与框架内的协议(protocol)对话。
例如主类 - AudioManager - 有一个 AudioPlayer,并且应该能够在其上调用一些内部函数,
例如pause(reason:) 但该方法应该是内部 并且不会暴露在框架之外。

这是一个示例。

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。 ..

或者你们这些程序员是怎么做到的?
如果不暴露供内部使用的方法和变量,框架会更漂亮!

谢谢!

最佳答案

不,没有更优雅的解决方案,至少在考虑协议(protocol)时,原因如下:

想象一个场景,有人使用你的框架想要为 AudioPlayerProtocol 编写一个扩展,如果 pause(reason:) 方法是内部的,那么如何实现它?

你可以通过子类化来实现它,这段代码实际上会编译:

public class AudioPlayer: AudioPlayerProtocol {
public func pause() {
pause(reason: .byUser)
}

internal func pause(reason: PauseReason) {
}
}

对于协议(protocol),情况并非如此,因为如果具有公共(public)访问级别的人想要使用您的混合公共(public)/内部协议(protocol),您根本无法保证内部功能的实现。

关于ios - 具有内部函数和属性的 Swift 公共(public)协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39751012/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com