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 委托在选项卡栏控制器内的所有继承视图控制器中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

从容器视图中的选项卡栏控制器中的视图控制器委派信息

存储在应用程序委托中的对象似乎不存在

在启动时以编程方式为 5 个选项卡栏项目设置选项卡栏标题,其中 4 个嵌入在导航控制器中,1 个没有。目标 C

iOS:选择选项卡之前的选项卡栏项目标题

集合视图/选项卡栏控制器崩溃

在整个应用程序中重新调用应用程序委托