菜鸟教程小白 发表于 2022-12-11 18:16:54

ios - AVPlayer 类的实例已被释放,而键值观察者仍向其注册


                                            <p><p>以下代码在为另一个 ViewController 推送 Controller 时崩溃。获取关注错误。</p>

<blockquote>
<p>***** Terminating app due to uncaught exception &#39;NSInternalInconsistencyException&#39;, reason: &#39;An instance 0x600000009690 of class AVPlayer was deallocated while key value observers were still registered with it. Current observation info:(
   Context: 0x0, Property: 0x600000446ea0&gt;
)&#39;**</p>
</blockquote>

<pre><code>//MARK: tableViewMethods

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int
{
    return arrVideoListing.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell
{
    //print(&#34;cell for row&#34;)
    cell = tableView.dequeueReusableCell(withIdentifier: &#34;DashboardVideoListingCell&#34;, for: indexPath) as! DashboardVideoListingCell

    cell.lblUserName.text = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;user_name&#34;) as? String
    let videoName = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;video_title&#34;) as? String
    cell.lblHashTag.text = self.replaceChar(videoName!)

    cell.lblAddedTime.text = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;datetime&#34;) as? String
    cell.lblCategory.text = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;category&#34;) as? String

    cell.lblVotes.text = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;votes&#34;) as! String

    cell.lblDislikes.text = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;negative_votes&#34;) as! String

    cell.lblViews.text = &#34;\((arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;views&#34;) as! String) views&#34;

    cell.btnFullScreen.tag = indexPath.row
    cell.btnFullScreen.addTarget(self, action: #selector(fullScreenBtnClicked(_:)), for: .touchUpInside)


    cell.btnPlayPause.isHidden = true
    cell.imgPlay.isHidden = true


    if (selectedRow1 !=&#34;&#34;)
    {
      if selectedRow1 == &#34;\(indexPath.row)&#34; &amp;&amp; isBtnShow == true
      {

            cell.btnPlayPause.isHidden = false
            cell.imgPlay.isHidden = false

      }
    }

    var temp: Int = getVisibleIndex()
    if temp == indexPath.row &amp;&amp; fullvisible
    {
      cell.imgC.frame = CGRect(x: cell.playerView.frame.origin.x+5, y: cell.playerView.center.y+135, width: 20, height: 20)
      cell.imgC.image = UIImage (named: &#34;C&#34;)

      cell.imgUserProfile.image = nil
      let imgurl1 = ((arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;user_data&#34;)as AnyObject).value(forKey: &#34;profile_picture&#34;)as? String
      if imgurl1 == &#34;&#34;
      {
            cell.imgUserProfile.image = UIImage (named: &#34;no_user_1.png&#34;)
      }
      else
      {
            let url1 = NSURL(string:imgurl1!)
            cell.imgUserProfile.imageURL = url1 as URL?
      }

            cell.btnUserInfo.tag = indexPath.row
            cell.btnUserInfo.addTarget(self, action: #selector(getUserInfoFromBtnClicked(_:)), for: .touchUpInside)

            let videoURL = NSURL(string: ((arrVideoListing.object(at:indexPath.row) as AnyObject).value(forKey: &#34;url&#34;) as AnyObject) as! String)
            print(videoURL!)
            cell.playerView.isHidden = false



            player = AVPlayer(url: videoURL! as URL)

            let playerLayer = AVPlayerLayer(player: player)
            playerLayer.frame = (cell.playerView.bounds)
            playerLayer.backgroundColor = UIColor.black.cgColor
            cell.layer.addSublayer(playerLayer)
            cell.playerView?.layer.addSublayer(playerLayer)
            cell.playerView.addSubview(cell.imgC)

            activityView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
            activityView.center = cell.playerView.center
            activityView.startAnimating()
            cell.playerView.addSubview(activityView)
            addedObserver = true


            player.addObserver(self, forKeyPath: &#34;status&#34;, options:[], context: nil)


            cell.selectionStyle = .none
            NotificationCenter.default.addObserver(self, selector: #selector(self.itemDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)

      }
      else
      {
            cell.playerView.isHidden = true
            cell.imgThumbnail.image = nil
            let imgurl = (arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;thumbnail&#34;)as? String
            let url = NSURL(string:imgurl!)
            cell.imgThumbnail.imageURL = url as URL?

            cell.imgUserProfile.image = nil
            let imgurl1 = ((arrVideoListing.object(at: indexPath.row)as AnyObject).value(forKey: &#34;user_data&#34;)as AnyObject).value(forKey: &#34;profile_picture&#34;)as? String
            if imgurl1 == &#34;&#34;
            {
                cell.imgUserProfile.image = UIImage (named: &#34;no_user_1.png&#34;)
            }
            else
            {
                let url1 = NSURL(string:imgurl1!)
                cell.imgUserProfile.imageURL = url1 as URL?
            }

            cell.btnPlayPause.tag = indexPath.row
            cell.btnPlayPause.addTarget(self, action: #selector(playVideoFromBtnClicked(_:)), for: .touchUpInside)

            cell.btnUserInfo.tag = indexPath.row
            cell.btnUserInfo.addTarget(self, action: #selector(getUserInfoFromBtnClicked(_:)), for: .touchUpInside)

            cell.selectionStyle = .none
            if player != nil
            {
                player.pause()
            }
            cell.backgroundColor = UIColor .blue

            return cell
       }
    return cell
}

func getVisibleIndex() -&gt; Int
{
    for indexPath: IndexPath in tblVideoListing.indexPathsForVisibleRows!
    {
      let cellRect: CGRect = tblVideoListing.rectForRow(at: indexPath)
      let isVisible: Bool = tblVideoListing.bounds.contains(cellRect)
      if isVisible
      {
            index = Int(indexPath.row)
      }
    }
    return index
}

func scrollViewDidScroll(_ aScrollView: UIScrollView)
{

    let cells: = tblVideoListing.visibleCells as!
    vara = 0
    for cell: DashboardVideoListingCell in cells
    {
      let path: IndexPath? = IndexPath(row: a, section: 0)
      index = Int((path?.row)!)
      fullvisible = true
      a= a + 1
    }

}


func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
{

    do {

      tblVideoListing.reloadData()

    }
    catch
    {
      print(error.localizedDescription)
    }


}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: ?, context: UnsafeMutableRawPointer?)
{

    if (keyPath == &#34;status&#34;) {

      if player.status == .readyToPlay {

            player.play()
            if player.rate&gt;=0
            {
                addedObserver = false


                if(player != nil &amp;&amp; player.currentItem != nil)
                {

                  player.removeObserver(self, forKeyPath: &#34;status&#34;, context: nil)
                }


                activityView.removeFromSuperview()

            }
      }
      else if player.status == .failed {

      }
    }
}


deinit
{
    if addedObserver == true
    {
      if(player != nil &amp;&amp; player.currentItem != nil)
      {
            player.removeObserver(self, forKeyPath: &#34;status&#34;, context: nil)

      }
    }
}

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
    if player != nil
    {
      player.pause()
    }
}
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>为每个 <code>cellForRowAt</code> 创建一个新播放器,为什么?</p>

<p>崩溃的原因大概是这行:<br/>
<code>player = AVPlayer(url: videoURL! as URL)</code>
如果 <code>player</code> 已经存在,那么它将被释放 - 如果它有观察者(它有),它将产生崩溃。</p>

<p>两个建议:<br/>
1. 不要在 <code>cellForRowAt</code> 中创建新播放器,为您的 ViewController 创建一个全局播放器(推荐)</p>

<p>或</p>

<ol 开始=“2”>
<li><p>记得在创建新玩家之前移除观察者</p>

<p>player.removeObserver(self, forKeyPath: "status", context: nil)<br/>
player = AVPlayer(url: videoURL! as URL)</p></li>
</ol></p>
                                   
                                                <p style="font-size: 20px;">关于ios - AVPlayer 类的实例已被释放,而键值观察者仍向其注册,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/45078417/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/45078417/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - AVPlayer 类的实例已被释放,而键值观察者仍向其注册