代码之家  ›  专栏  ›  技术社区  ›  Gthoma2

以某种方式生成AVPlayerItem的副本,而不是访问引用

  •  0
  • Gthoma2  · 技术社区  · 7 年前

    我有一个使用AVQueuePlayer对象的简单音频播放列表。队列通过迭代包含自定义UITableViewCell对象的UITableView填充,即PlayableAudioCell。这些对象有一个AVPlayerItem属性audioTrack,我将其插入AVQueueplayer的队列中。

    我想在播放和完成这些曲目时添加和删除AVPlayerItemDidPlayToEndTime观察者,以便更新我创建的音乐播放器的标签。

    出于某种原因,如果队列长于2个曲目,则队列中的第三个曲目不会将观察者添加到队列中,因为应用它的函数会传递一个曲目的副本,而不是保存到PlayableAudioCell对象的曲目。

    只是一些关于我的应用程序布局的解释。。。它包含一个视图,即tableViewController,允许用户选择单元格并播放曲目。我还有一个SplitViewController,它允许一个FooterView弹出并显示播放轨迹信息(标签、持续时间、轨迹滑块)。

    操作顺序:

    1. 用户在TableView中的单元格上按play

    2. TableViewController的委托(FooterViewController)调用其委托的播放方法

    3. AVPlayerItemDidPlayToEndTime观察器添加到播放的第一项中

    4. 当轨迹结束时,从观测器调用选择器。在该选择器中,删除当前轨迹的观察者,并添加将AVPlayerItemDidPlayToEndTime观察者添加到下一个轨迹的代码。

    与引用currentlySelectedAudioCell的audiotrack属性相反,当我访问单元格的副本或音轨的副本时,是否会弹出任何代码?

    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()
    
            }
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   Gthoma2    7 年前

    显然,AVQueuePlayer每次播放完队列中的项目时都会删除一个AVPlayerItem。我的逻辑是尝试将队列的索引与tableview单元格数组相匹配,经过几次迭代后,索引将关闭,观测者将无法添加到正确的playeritem。通过使用AVPlayer和AVPlayerItems数组替换AVQueuePlayer修复。