2017-10-18 79 views
0

我有一個簡單的音頻播放列表使用AVQueuePlayer對象。該隊列通過遍歷包含自定義UITableViewCell對象的UITableView(PlayableAudioCell)來填充。這些對象有一個AVPlayerItem屬性audioTrack,我將它插入到AVQueueplayer的隊列中。以某種方式生成AVPlayerItem的副本,而不是訪問參考

我想在播放和完成項目時將AVPlayerItemDidPlayToEndTime觀察者添加到這些軌道並將其刪除,以便我可以更新我創建的音樂播放器的標籤。

由於某些原因,如果隊列長於2個軌道,隊列中的第三個軌道不會將觀察者添加到它,因爲應用它的函數傳遞軌道的副本,而不是跟蹤保存到PlayableAudioCell對象的軌道。

我不明白這是怎麼回事,但我必須創建一個軌道的副本,而不是引用單元格的音軌。我可以從音軌的內存位置的打印語句中知道我是誰。

只是對我的應用程序的佈局的一些解釋...它包含一個視圖是tableViewController,允許用戶選擇一個單元格和播放曲目。我也有一個SplitViewController,允許FooterView彈出並顯示播放曲目信息(標籤,持續時間,曲目滑塊)。操作

訂單:

  1. 用戶按下TableView中

  2. AudioQueuePlayer的隊列中的細胞發揮被按下的軌跡和它下面

  3. TableViewController的委託每條軌道填充(FooterViewController)調用它的委託播放方法

  4. AVP layerItemDidPlayToEndTime觀察者被添加到正在播放的第一個項目

  5. 當曲目結束時,選擇器從觀察者被調用。在這個選擇器中,當前軌道的觀察者被移除,並添加將AVPlayerItemDidPlayToEndTime觀察者添加到下一個軌道的代碼。

是否有這個代碼的彈出作爲我訪問細胞或audiotrack副本的副本,而不是引用currentlySelectedAudioCell的audiotrack財產?

我會忽略我的代碼在TableViewController ......我可以告訴大家,它被正確填充表內和問題必須位於FooterViewController的代碼中:

func play(cell: PlayableAudioCell){ 

    if let previousCell = currentlySelectedAudioCell, let prevFilename = currentlySelectedAudioCell?.chapter?.value(forKey: "Filename") as? String, let filename = cell.chapter?.value(forKey: "Filename") as? String{ 

     if filename != prevFilename{ 
      runningTime = 0 
     } 
    } 

    updateWithObserver(cell: cell) 

    //show footerview if it is hidden. 
    if(footerView.superview?.isHidden)!{ 
     hideShowFooterView() 
    } 

    if(self.isPlaying)!{ 
     //print("Should pause cell") 
     audioQueuePlayer?.pause() 
     switchState(state: "Pause") 

     playPauseRunTime(state: "Pause") 

    }else{ 
     //print("Should play cell") 
     audioQueuePlayer?.play() 
     switchState(state: "Play") 

     playPauseRunTime(state: "Play") 
    } 

    updateFooterView() 
} 

func updateWithObserver(cell: PlayableAudioCell){ 

    self.currentlySelectedAudioCell = cell 
    delegate?.currentlySelectedAudioCell = cell 

    let track = cell.audioTrack! 

    NotificationCenter.default.addObserver(self, selector: #selector(FooterViewController.playerItemDidReachEnd(notification:)), name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: track) 

} 

func playerItemDidReachEnd(notification: Notification){ 
    NotificationCenter.default.removeObserver(self, name: notification.name, object: audioQueuePlayer?.currentItem) 

    if didAudioPlayEntirely(){ 
     recordAudioHistoryToFirebase(didFinish: true) 
     if let currentlySelectedAudioCell = delegate?.currentlySelectedAudioCell{ 
      revealCheckMark(cell: currentlySelectedAudioCell) 
     } 
    } 

    runningTime = 0 

    //If there is just one more item in the queue, regardless of whether playAll() has been toggled... 
    if (audioQueuePlayer?.items().count)! <= 1 { 

     playPauseRunTime(state: "Pause") 

     audioQueuePlayer?.removeAllItems() 
     resetFooterViewUI() 
     switchState(state: "Pause") 
     hideShowFooterView() 

     audioQueuePlayer?.rate = 0.0 

     delegate?.currentlySelectedAudioCell = nil 
     currentlySelectedAudioCell = nil 
     delegate?.indexPathOfSelectedCell = nil 
     indexPathOfSelectedCell = nil 

    }else{ 

     if let indexPathOfSelectedCell = indexPathOfSelectedCell{ 

      playPauseRunTime(state: "Pause") 
      playPauseRunTime(state: "Play") 

      let row = indexPathOfSelectedCell.row + 1 
      let newIndexPath = IndexPath(row: row, section: 0) 
      self.indexPathOfSelectedCell = newIndexPath 
      delegate?.indexPathOfSelectedCell = newIndexPath 

      let newCell = self.tableView!.cellForRow(at: newIndexPath) as? PlayableAudioCell 
      updateWithObserver(cell: newCell!) 

      updateFooterView() 
      self.tableView!.reloadData() 

     } 
    } 
} 

回答

0

顯然AVQueuePlayer每次完成播放其隊列中的項目時,都會刪除AVPlayerItem。我的邏輯是試圖將隊列的索引與tableview單元格的數組進行匹配,經過幾次迭代後,索引將關閉,並且觀察者不會被添加到正確的播放項目中。通過用AVPlayer和AVPlayerItems數組替換AVQueuePlayer來修復。

相關問題