BaseController 委托在选项卡栏控制器内的所有继承视图控制器中不起作用
Posted
技术标签:
【中文标题】BaseController 委托在选项卡栏控制器内的所有继承视图控制器中不起作用【英文标题】:BaseController delegate not working in all inherited view controllers inside tab bar controller 【发布时间】:2016-12-22 16:04:15 【问题描述】:我很难理解为什么我在基本控制器中定义的委托不能在继承的视图控制器中工作。
我有一个 TabBarController,它有 2 个 ViewController。每个 ViewController 都是 BaseController 的子类。
BaseController 实现一个委托并更新一个标签视图。
当我启动应用程序并单击播放时,FirstVC 会更新标签,但是当我将选项卡切换到 SecondVC 时,它会开始更新,但是当我再次单击 FirstVC 时,更新卡住并且不会更新标签,但标签会不断更新在 SecondVC 中。
import Foundation
import AVFoundation
protocol SharedPlayerNotificaions : class
func willPlay(status: Bool)
func currentPlayTime(timeString: String)
class SharedPlayer : NSObject
static let sharedInstance = SharedPlayer()
private var player : AVPlayer?
weak var delegate : SharedPlayerNotificaions?
override private init()
super.init()
player = AVPlayer()
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>)
if keyPath == "status"
if player?.status == AVPlayerStatus.Unknown
delegate?.willPlay(false)
if player?.status == AVPlayerStatus.Failed
print("failed")
delegate?.willPlay(false)
if player?.status == AVPlayerStatus.ReadyToPlay
print("readytoplay")
delegate?.willPlay(true)
if keyPath == "rate"
if keyPath == "duration"
func play()
player?.play()
let interval = CMTime(value: 1, timescale: 2)
player?.addPeriodicTimeObserverForInterval(interval, queue: dispatch_get_main_queue(), usingBlock: (progressTime) in
let seconds = CMTimeGetSeconds(progressTime)
let secondsString = String(format: "%02d", Int(seconds % 60))
let minutesString = String(format: "%02d", Int(seconds / 60))
self.delegate?.currentPlayTime("\(minutesString):\(secondsString)")
)
func setUrl(urlString: String)
if let url = NSURL(string: urlString)
player = AVPlayer(URL: url)
player?.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: nil)
player?.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)
player?.addObserver(self, forKeyPath: "duration", options: NSKeyValueObservingOptions.New, context: nil)
基础控制器
class BaseController : UIViewController, SharedPlayerNotificaions
let label = UILabel()
override func viewDidLoad()
SharedPlayer.sharedInstance.delegate = self
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 1, constant: 10))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 50))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1, constant: 10))
label.text = "00:00"
func currentPlayTime(timeString: String)
dispatch_async(dispatch_get_main_queue())
self.label.text = timeString
func willPlay(status: Bool)
FirstViewController
class FirstViewController: BaseController
@IBAction func playButton(sender: AnyObject)
let urlString = "https://someStreamUrl"
SharedPlayer.sharedInstance.setUrl(urlString)
SharedPlayer.sharedInstance.play()
第二视图控制器
class SecondViewController : BaseController
override func viewDidLoad()
super.viewDidLoad()
view.backgroundColor = .redColor()
【问题讨论】:
【参考方案1】:主要缺陷是SharedPlayer
是单例。只有一个实例。它只能有一个代表。但是您创建了两个视图控制器。两者都试图告诉单个共享 SharedPlayer
实例它是委托。第二个获胜。
委托模式仅在有一个委托时有效。在这种情况下,您有两个,因此您不能使用传统的委托模式。
有几种可能的解决方案。
-
更新
SharedPlayer
以接受委托数组而不是单个委托。
使用NSNotificationCenter
。让SharedPlayer
发布通知,并让每个视图控制器注册每个可能的通知。
【讨论】:
谢谢,我选择你的答案是正确的。但是,如果我可以问你能帮我设计一个更好的设计吗?我正在尝试构建一个 MusicPlayer 应用程序,其中 basecontroller 具有播放器视图,并且在我的 tabBarController 内所有 VC 都继承自该应用程序,我只是试图通过从互联网上学习所有内容来构建应用程序。 为什么SharedPlayer
是单身人士?为什么要在多个标签中使用相同的AVPlayer
?为什么每个标签不能有自己的播放器?
SharedPlayer 是一个单例,因为我需要使用这个播放器播放多首歌曲,如果我点击下一首或上一首歌曲,它应该可以工作,当我更改标签时,播放器视图将根据avplayer 否则我如何更新视图?以上是关于BaseController 委托在选项卡栏控制器内的所有继承视图控制器中不起作用的主要内容,如果未能解决你的问题,请参考以下文章