title: Swift Public protocols with Internal functions and properties
body: <p>I am wondering what the best practice is when I want some functions to be public and some to me internal when working with protocols.<br><br>I am writing an <a href="https://github.com/Sajjon/SwiftAudioManager" rel="noreferrer">AudioManager</a> in <strong>Swift 3</strong> wrapping <code>AVPlayer</code> as a framework.<br><br> I want some methods to be public, so that e.g. a ViewController making use of the AudioManager can access some methods, but some methods would not be exposed outside the framework<br> -> i.e. having the access modifier <code>internal</code> instead of <code>public</code>.<br><br> I am writing the framework with protocol driven design, almost every part should have a protocol.<br>So protocols are talking to protocols within the framework.<br> E.g. the main class - <code>AudioManager</code> - has an <code>AudioPlayer</code>, and should be able to call some <code>internal</code> functions on it,<br> e.g. <code>pause(reason:)</code> but that method should be <code>internal</code> and not exposed outside the framework.<br><br>Here is an example.</p>
  
  <pre><code>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()
      }
  }
  </code></pre>
  
  <p><strong>I know I can get it to work by changing the method <code>pauseBecauseOfRouteChange</code> to look like this:</strong></p>
  
  <pre><code>func pauseBecauseOfRouteChange() {
      guard let internalPlayer = audioPlayer as? InternalAudioPlayerProtocol else { return }
      internalPlayer.pause(reason: .routeChange)
  }
  </code></pre>
  
  <p><strong>But I am wondering if there is a more elegant solution?<br></strong> Something like marking that the <code>AudioPlayerProtocol</code> refines the <code>InternalAudioPlayerProtocol</code>...</p>
  
  <p>Or how do you fellow programmers do it?<br>The framework is more beautiful if it does not expose methods and variables that are intended for internal use!</p>
  
  <p>Thanks!</p>