【问题标题】:Add ActivityIndicator and remove addObserver on AVPlayer在 AVPlayer 上添加 ActivityIndi​​cator 并移除 addObserver
【发布时间】:2016-07-24 17:06:12
【问题描述】:

我试图在播放器(缓冲或加载)时显示ActivityIndicator,当它开始播放时它停止ActivityIndicator。此外,当我停止播放器时,它(removeObserver 或 deallocObservers)是 AVPlayer。 当我播放音乐时,它会显示 ActivityIndicator 直到它准备好播放,但它会在播放前 4.5 秒停止为 ActivityIndi​​cator 设置动画。问题是当我停止 AVPlayer 或点击另一个播放按钮时,它会在删除 AVPlayer 观察者时给我错误。 谁能告诉我代码中的错误在哪里以及如何修复它,谢谢。

var selectIndex:Int = -1

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! RadioCollectionViewCell
        cell.backgroundColor = UIColor.yellowColor()

        let object = objects[indexPath.row]
        cell.img.image = UIImage(named: object["image"]!)
        cell.btnPlay.addTarget(self, action: Selector("audioControlButtonAction:"), forControlEvents: UIControlEvents.TouchUpInside)
        cell.btnPlay.tag = indexPath.row+1


        return cell
    }

func audioControlButtonAction(sender: UIButton){

        if player != nil && player?.currentItem != nil {
            deallocObservers(player!)
        }

        var btn:NSInteger
        btn = sender.tag as NSInteger

        let object = objects[btn-1]
        let nurl = NSURL(string: "\(object["url"]!)")!
        playerItem = AVPlayerItem(URL: nurl)
        player=AVPlayer(playerItem: playerItem!)

        print(selectIndex)
        if selectIndex != -1 && selectIndex != sender.tag
        {
            let bt:UIButton = self.view.viewWithTag(selectIndex) as! UIButton

            if bt.selected == true
            {
                bt.selected = false
                deallocObservers(player!)
            }
        }

        if sender.selected == false
        {
            player!.addObserver(self, forKeyPath: "status", options:NSKeyValueObservingOptions(), context: nil)
            player!.addObserver(self, forKeyPath: "playbackBufferEmpty", options:NSKeyValueObservingOptions(), context: nil)
            // player!.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options:NSKeyValueObservingOptions(), context: nil)
            player!.addObserver(self, forKeyPath: "loadedTimeRanges", options: NSKeyValueObservingOptions(), context: nil)

            player!.play()
            sender.selected = true
            selectIndex = sender.tag
            activityView.startAnimating()
            // self.view.userInteractionEnabled = false


        }
        else
        {

            deallocObservers(player!)
            player?.pause()
            sender.selected = false
            selectIndex = -1
        }

        print(selectIndex)

    }

    func deallocObservers(player: AVPlayer) {

        player.removeObserver(self, forKeyPath: "status")
        player.removeObserver(self, forKeyPath: "playbackBufferEmpty")
        // player.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
        player.removeObserver(self, forKeyPath: "loadedTimeRanges")
    }


    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>){

        if object?.isEqual(player) == true && keyPath == "status" {
            print("status")

            if player?.status == AVPlayerStatus.ReadyToPlay{
                print("AVPlayerStatus.ReadyToPlay")
                activityView.stopAnimating()
                // self.view.userInteractionEnabled = true
            }else{
                print("AVPlayerStatus.NotReadyToPlay")
                activityView.startAnimating()
//                self.view.userInteractionEnabled = false
            }

          //if keyPath == "playbackLikelyToKeepUp" {
               //activityView.stopAnimating()
               ////self.view.userInteractionEnabled = true
               //print("playbackLikelyToKeepUp")
            //}
            if keyPath == "playbackBufferEmpty" {
                activityView.startAnimating()
                self.view.userInteractionEnabled = false

                let createAccountErrorAlert: UIAlertView = UIAlertView()
                createAccountErrorAlert.delegate = self
                createAccountErrorAlert.title = "No Internet Connection"
                createAccountErrorAlert.message = "Make sure your device is connected to the internet."
                createAccountErrorAlert.addButtonWithTitle("Dismiss")

                createAccountErrorAlert.show()

                print("playbackBufferEmpty")
            }

            if player?.status == AVPlayerStatus.Failed{
                print("Something went wrong . player.error should contain some information")
            }
        }
    }

输出

-1
1
status
AVPlayerStatus.ReadyToPlay
1
2016-07-24 21:51:00.585 Radio[777:23560] *** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <Radio.RadioCollectionViewController 0x7fbe39d47f70> for the key path "status" from <AVPlayer 0x7fbe39e67410> because it is not registered as an observer.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001019b2e65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000103b51deb objc_exception_throw + 48
    2   CoreFoundation                      0x00000001019b2d9d +[NSException raise:format:] + 205
    3   Foundation                          0x0000000101fc4d51 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 504
    4   Foundation                          0x0000000101fc4abd -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 84
    5   Radio                               0x00000001014a935d _TFC5Radio29RadioCollectionViewController16deallocObserversfS0_FCSo8AVPlayerT_ + 141
    6   Radio                               0x00000001014a8fbe _TFC5Radio29RadioCollectionViewController24audioControlButtonActionfS0_FCSo8UIButtonT_ + 5326
    7   Radio                               0x00000001014a92ba _TToFC5Radio29RadioCollectionViewController24audioControlButtonActionfS0_FCSo8UIButtonT_ + 58
    8   UIKit                               0x0000000102630194 -[UIApplication sendAction:to:from:forEvent:] + 92
    9   UIKit                               0x000000010279f6fc -[UIControl sendAction:to:forEvent:] + 67
    10  UIKit                               0x000000010279f9c8 -[UIControl _sendActionsForEvents:withEvent:] + 311
    11  UIKit                               0x000000010279eaf8 -[UIControl touchesEnded:withEvent:] + 601
    12  UIKit                               0x000000010269f49b -[UIWindow _sendTouchesForEvent:] + 835
    13  UIKit                               0x00000001026a01d0 -[UIWindow sendEvent:] + 865
    14  UIKit                               0x000000010264eb66 -[UIApplication sendEvent:] + 263
    15  UIKit                               0x0000000102628d97 _UIApplicationHandleEventQueue + 6844
    16  CoreFoundation                      0x00000001018dea31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    17  CoreFoundation                      0x00000001018d495c __CFRunLoopDoSources0 + 556
    18  CoreFoundation                      0x00000001018d3e13 __CFRunLoopRun + 867
    19  CoreFoundation                      0x00000001018d3828 CFRunLoopRunSpecific + 488
    20  GraphicsServices                    0x0000000106247ad2 GSEventRunModal + 161
    21  UIKit                               0x000000010262e610 UIApplicationMain + 171
    22  Radio                               0x00000001014afd5d main + 109
    23  libdyld.dylib                       0x000000010468892d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

我找到了从该链接中删除status observer 的解决方案,但不知道如何快速转换它。

解决方案

@try { [player removeObserver:self forKeyPath:@"status"]; } @catch (NSException *exception) { } @finally { } –

【问题讨论】:

    标签: ios objective-c swift swift2 avplayer


    【解决方案1】:

    快速版本

    目标 C

    @try { [player removeObserver:self forKeyPath:@"status"]; } @catch (NSException *exception) { } @finally { } 
    

    斯威夫特

    Error Handling in Swift2

    do {
              try player.removeObserver(self, forKeyPath: "status")
            }
    
      catch {
        print("error")
      }
        defer{
          print("finally statement here")
        }
    

    【讨论】:

    • 感谢 Chandan Prajapati。现在我已经看到这个问题是由于我再次播放音乐时再次调用deallocObservers(player!) 造成的。因为当我再次播放音乐时。它进入if player != nil &amp;&amp; player?.currentItem != nil { deallocObservers(player!) }
    【解决方案2】:

    问题是“deallocObservers”方法被调用了两次,而这两次调用之间没有添加任何观察者。我想曾经在这里:

        if player != nil && player?.currentItem != nil {
            deallocObservers(player!)
        }
    

    第二次调用此方法时,播放器变量和当前项目不会为空。第二次调用 deallocObservers 可能在这里:

            if bt.selected == true
            {
                bt.selected = false
                deallocObservers(player!)
            }
    

    我会在 deallocObservers 方法中放置一个断点,以查看该方法被调用了多少次以及谁调用了它(查看堆栈跟踪)。

    【讨论】:

    • 现在我从if bt.selected == true 和暂停方法中删除“deallocObservers”。我已经看到使用断点,当我暂停它时删除观察者,但是当我再次播放它时,它再次继续if player != nil &amp;&amp; player?.currentItem != nil 方法,所以观察者已经被删除,因此由于这个原因它给了我同样的错误。你知道我需要添加什么条件吗?谢谢
    • 我会从 if bt.selected == true 中删除 deallocObservers(player!) 调用。真的需要吗?
    【解决方案3】:

    我添加了对这些条件的检查。

    var check = true
    func audioControlButtonAction(sender: UIButton){
    
            if check == false {
                deallocObservers(player!)
            }
            if sender.selected == false{
                check = false
            }
            else{
                check = true
            }        
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-16
      • 1970-01-01
      • 2019-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多