2016-09-28 29 views
5

Bazı işlevlerin genel ve bazılarının benimkilerle iletişim kurarken ne kadar içsel olmasını istediğinizi en iyi uygulamanın ne olduğunu merak ediyorum.

Bir çerçeve olarak AVPlayer sarmasını Swift 3 içinde bir AudioManager yazıyorum.

Bazı yöntemlerin herkese açık olmasını istiyorum, böylece örn. AudioManager'dan yararlanan bir ViewController bazı yöntemlere erişebilir, ancak bazı yöntemler
çerçevesinin dışına çıkmayacaktır -> i.e. public yerine erişim değiştiricisi internal.

Protokol odaklı tasarım ile çerçeve yazıyorum, neredeyse her bölüm bir protokol olmalıdır.
Bu yüzden protokoller çerçeve içindeki protokollerle konuşuyor.
E.g. Ana sınıf - AudioManager - AudioPlayer içeriyor ve internal işlevlerini,
vb. pause(reason:) ancak bu yöntem internal olmalıdır ve çerçevenin dışında gösterilmemelidir.

İşte bir örnek.Swift Dahili işlevler ve özelliklere sahip Genel iletişim kuralları

func pauseBecauseOfRouteChange() { 
    guard let internalPlayer = audioPlayer as? InternalAudioPlayerProtocol else { return } 
    internalPlayer.pause(reason: .routeChange) 
} 

Ama daha zarif bir çözüm olup olmadığını merak ediyorum:

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() 
    } 
} 

ben böyle bakmak yöntemi pauseBecauseOfRouteChange değiştirerek işe alabilirim biliyor? AudioPlayerProtocolInternalAudioPlayerProtocol yeniler olduğunu işaretleme gibi
şey ...

Yoksa dost programcılar bunu nasıl yapacağım?
Çerçeve, iç kullanım için tasarlanmış yöntemleri ve değişkenleri ortaya çıkarmazsa daha güzeldir!

Teşekkürler!

Birisi çerçevesini kullanarak AudioPlayerProtocol için bir uzantı yazmak istediği bir senaryo, ne kadar sonra pause(reason:) düşünün:

cevap

0

Hayır, neden en azından burada protokolleri dikkate ve ne zaman, hiçbir, bu daha şık bir çözüm yoktur yöntem dahili ise uygulanabilir mi?

Sadece sınıflara ve bu kodun gerçekten derlemek olacak bunu elde edebilirsiniz: protokolleri ile

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

    internal func pause(reason: PauseReason) { 
    } 
} 

bu durum böyle değil, kamu erişim düzeyine sahip birinin istiyorsa sadece iç fonksiyonun uygulanmasını garanti edemez çünkü karma ortak/iç protokolünü kullanın.

0

Protokolünüzü iç ve genel olarak bölüştürüp genel uygulama sınıfının bir iç uygulamaya yetki vermesine izin verin.

internal protocol InternalAudioPlayerProtocol { 
    func pause(reason: PauseReason) 
} 

public protocol AudioPlayerProtocol { 
    func pause() 
} 

internal class InternalAudioPlayer: InternalAudioPlayerProtocol { 
    internal func pause(reason: PauseReason) { 
    } 
} 

public class AudioPlayer: AudioPlayerProtocol { 
    internal var base: InternalAudioPlayerProtocol 

    internal init(base: InternalAudioPlayerProtocol) { 
     self.base = base 
    } 

    public func pause() { 
     base.pause(reason: .byUser) 
    } 
} 

public protocol AudioManagerProtocol { 
    var audioPlayer: AudioPlayerProtocol { get } 
} 

public class AudioManager: AudioManagerProtocol { 
    internal let base = InternalAudioPlayer() 
    public let audioPlayer: AudioPlayerProtocol 

    public init() { 
     audioPlayer = AudioPlayer(base: base) 
    } 

    internal func handleSomeNotification() {    
     pauseBecauseOfRouteChange() //amongst other things 
    } 

    internal func pauseBecauseOfRouteChange() { 
     base.pause(reason: .routeChange) 
    } 
}