我正在构建一个具有tableView的应用程序,其中包含一个带有音乐曲目URL的帖子。当帖子完全可见时,我的播放器开始播放帖子轨道。在播放过程中,我应该在帖子中的波形视图中显示播放进度。
问题是观察只能正常使用3个第一个单元格,因为下一个单元格wavePlot不会更新并且寻求停止工作。
我不知道造成这个问题的原因。任何帮助表示赞赏。
这是一个布局:
在我的viewController的viewDidLoad中,我使用addPeriodicTimeObserver初始化AVPlayer观察者,并将其返回类型分配给变量playerObserver。
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
timeLinePostsArray = User.sharedUser.requestTimelineData()
playerObserver = StreamMusicPlayer.shared.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 2),
queue: DispatchQueue.main,
using: { (progress) in
if StreamMusicPlayer.shared.isPlaying {
self.cellToObserve?.updatePlot(with: progress)
}
})
}
以下是我用来检测完全可见细胞的代码。当检测到完全可见的单元格时,我将其分配给变量cellToObserve以供观察者使用并开始播放单元格的音乐轨道。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
for item in tableView.indexPathsForVisibleRows!{
if tableView.bounds.contains(tableView.rectForRow(at: item)){
let fullyVisibleCell = tableView.cellForRow(at: item) as! HomeControllerTableViewCell
if StreamMusicPlayer.currentItemURL != fullyVisibleCell.containedMusicTrack?.trackURL.absoluteString {
//Play music track and observe the playback progress
self.cellToObserve = fullyVisibleCell
self.numberOfCellToObserve = tableView.indexPath(for: fullyVisibleCell)?.row
fullyVisibleCell.playButton.isEnabled = true
fullyVisibleCell.plot.isUserInteractionEnabled = true
StreamMusicPlayer.playItem(musicTrack: fullyVisibleCell.containedMusicTrack!)
}
} else {
let _cell = tableView.cellForRow(at: item) as! HomeControllerTableViewCell
_cell.plot.isUserInteractionEnabled = false
_cell.playButton.isEnabled = false
}
}
}
在viewController的deinit方法中,我尝试删除玩家的观察者。
func attemptRemoveObservation() {
if self.playerObserver != nil {
StreamMusicPlayer.shared.removeTimeObserver(self.playerObserver)
self.playerObserver = nil
}
}
deinit {
self.attemptRemoveObservation()
}
这是我的玩家的实施:
class StreamMusicPlayer: AVPlayer {
private override init(){
super.init()
}
static var currentItemURL: String?
static var shared = AVPlayer()
static func playItem(musicTrack: MusicTrack) {
let item = AVPlayerItem(url: musicTrack.trackURL)
StreamMusicPlayer.shared.replaceCurrentItem(with: item)
StreamMusicPlayer.currentItemURL = musicTrack.trackURL.absoluteString
StreamMusicPlayer.shared.play()
}
}
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
如果需要,这里是完整的viewController的源代码:
//
// HomeViewController.swift
// CheckMyTrack
//
// Created by Alexey Savchenko on 09.03.17.
// Copyright © 2017 Alexey Savchenko. All rights reserved.
//
import UIKit
import CoreMedia
import Foundation
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
//MARK: Vars
var playerObserver: Any!
var timeLinePostsArray: [TimeLinePost] = []
var cellToObserve: HomeControllerTableViewCell?
var numberOfCellToObserve: Int?
//MARK: Outlets
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
timeLinePostsArray = User.sharedUser.requestTimelineData()
playerObserver = StreamMusicPlayer.shared.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 2),
queue: DispatchQueue.main,
using: { (progress) in
if StreamMusicPlayer.shared.isPlaying {
self.cellToObserve?.updatePlot(with: progress)
}
})
}
func attemptRemoveObservation(){
if self.playerObserver != nil{
StreamMusicPlayer.shared.removeTimeObserver(self.playerObserver)
self.playerObserver = nil
}
}
//MARK: TableView delegate methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return timeLinePostsArray.count
}
//TODO: Implement correct change of observing cell plot
func scrollViewDidScroll(_ scrollView: UIScrollView) {
for item in tableView.indexPathsForVisibleRows!{
if tableView.bounds.contains(tableView.rectForRow(at: item)){
let fullyVisibleCell = tableView.cellForRow(at: item) as! HomeControllerTableViewCell
if StreamMusicPlayer.currentItemURL != fullyVisibleCell.containedMusicTrack?.trackURL.absoluteString {
//Play music track and observe the playback progress
self.cellToObserve = fullyVisibleCell
self.numberOfCellToObserve = tableView.indexPath(for: fullyVisibleCell)?.row
fullyVisibleCell.playButton.isEnabled = true
fullyVisibleCell.plot.isUserInteractionEnabled = true
StreamMusicPlayer.playItem(musicTrack: fullyVisibleCell.containedMusicTrack!)
}
} else {
let _cell = tableView.cellForRow(at: item) as! HomeControllerTableViewCell
_cell.plot.isUserInteractionEnabled = false
_cell.playButton.isEnabled = false
}
}
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// if let _cell = cell as? HomeControllerTableViewCell{
// if self.playerToken != nil{
// StreamMusicPlayer.shared.removeTimeObserver(self.playerToken)
// self.playerToken = nil
// }
// }
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeViewControllerCell", for: indexPath) as? HomeControllerTableViewCell
let track = timeLinePostsArray[indexPath.row].musicTrack
cell?.containedMusicTrack = track
cell?.authorNameLabel.text = timeLinePostsArray[indexPath.row].authorName
cell?.authorPicture.image = timeLinePostsArray[indexPath.row].authorPicture
cell?.trackName.text = track.trackName
cell?.plot.populateWithData(from: track.trackWaveformData)
cell?.plot.normalColor = UIColor.gray
cell?.plot.progressColor = UIColor.orange
cell?.playAction = { (cell) in
if StreamMusicPlayer.shared.isPlaying {
if StreamMusicPlayer.currentItemURL == cell.containedMusicTrack?.trackURL.absoluteString {
cell.playButton.setImage(UIImage(named: "play"), for: .normal)
StreamMusicPlayer.shared.pause()
}
} else {
StreamMusicPlayer.shared.play()
cell.playButton.setImage(UIImage(named: "pause"), for: .normal)
}
}
cell?.likeAction = { (cell) in
}
return cell!
}
deinit {
self.attemptRemoveObservation()
}
}
答案 0 :(得分:0)
我找到了问题的根源。 有必要为我使用的自定义单元类实现prepareForReuse方法,并执行单元的波形图的清理。 WaveformPlot的波形属性需要明确清空。
我的实施如下:
override func prepareForReuse() {
plot.clearPlot()
plot.waveforms = []
}
func clearPlot(){
for item in self.subviews{
item.removeFromSuperview()
}
guard let layers = self.layer.sublayers else { return }
for _item in layers{
_item.removeFromSuperlayer()
}
}