ios - Avplayer 被创建了 2 次

标签 ios swift avplayer

我有一个创建 AVPlayer 的详细 Controller ,当我启动播放器时,然后我退出 Controller 并输入有关歌曲的数据未保存,当我单击播放时再次创建 AVPlayer。问题是如何让AVPlayer保存所有数据,而不必删除旧播放器。有问题的 Gif 下面

enter image description here

这是我的代码:

ViewControllerAudioInfo 是我获取歌曲数据的 Controller

 func request(){

    let urlData = "https:---.com/local/apps/apple/library_detail.php/?idLibrary=\(detail!.id!)"


    var urlRequest = URLRequest(url: URL(string: urlData)!)
    urlRequest.timeoutInterval = 300



    let task = URLSession.shared.dataTask(with: urlRequest) { (data,response,error) in

        if error != nil{
            print(error ?? 0)
            return
        }

        DispatchQueue.main.async {

            let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: Any]


            if let posts = json["FILE"] as? [AnyObject] {
                for post in posts {
                    var info = Modal()

                    info.AudioName = post["NAME"] as? String
                    info.UrlName = post["SRC"] as? String
                    info.ImageViewAudio = self.detail?.ImageView
                    info.AudioName = info.AudioName?.replacingOccurrences(of:".mp3", with: "")

                    self.mod.append(info)


                }
            }
        }

    }
    self.preloadEnd()
    task.resume()
}


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

     if segue.identifier == "audioDetail" {
        let destinationVC = segue.destination as! ViewControllerAudioDetail
        destinationVC.mod = mod
    }

    if segue.identifier == "list" {
        let destinationVC = segue.destination as! TableViewControllerAudioList
        destinationVC.mod = mod
    }
}

和细节 Controller

import UIKit  
import AVFoundation

class ViewControllerAudioDetail: UIViewController {


static var avPlayer:AVPlayer?
var status = false
var timeSlider = false
fileprivate let seekDuration: Float64 = 10
fileprivate let seekDurationThirty: Float64 = 30
var sliderEndTime:Any!
var sliderDurationTime:Any!


var mod = [Modal]()

@IBOutlet weak var menuButton: UIBarButtonItem!


@IBOutlet weak var ImageView: UIImageView!

@IBOutlet weak var startTime: UILabel!
@IBOutlet weak var endTime: UILabel!
@IBOutlet weak var sliderSong: UISlider!
@IBOutlet weak var name: UILabel!

@IBOutlet weak var Volume: UISlider!
@IBOutlet weak var iconChange: UIButton!


override func viewDidLoad() {
    super.viewDidLoad()


    //кнопка назад
    let backItem = UIBarButtonItem()
    backItem.title = ""
    navigationItem.backBarButtonItem = backItem

    menu()


    sliderSong.minimumValue = 0
    sliderSong.maximumValue = 1
    sliderSong.setThumbImage(UIImage(named: "thumb.png"), for: .normal)



    name.sizeToFit()
    name.text = mod[thisSong].AudioName
    ImageView.image = mod[0].ImageViewAudio

    player(urlSong:mod[thisSong].UrlName!)

    self.timeSlider = true
    self.status = true
    Status()


    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        let _ = try AVAudioSession.sharedInstance().setActive(true)
    } catch let error as NSError {
        print("an error occurred when audio session category.\n \(error)")
    }


}

func menu(){

    if revealViewController() != nil {

        menuButton.target = revealViewController()
        menuButton.action = #selector(SWRevealViewController.rightRevealToggle(_:))

        view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())


    }

}


@IBAction func sliderSong(_ sender: UISlider) {

        //перемотка аудиозвука
        let duration = CMTimeGetSeconds(ViewControllerAudioDetail.avPlayer!.currentItem!.asset.duration)
        let value = sliderSong.value
        let durationToSeek = Float(duration) * value

        ViewControllerAudioDetail.avPlayer?.seek(to: CMTimeMakeWithSeconds(Float64(durationToSeek),ViewControllerAudioDetail.avPlayer!.currentItem!.duration.timescale)) { [](state) in


            if (self.iconChange.currentImage?.isEqual(UIImage(named: "Play.png")))! {
                ViewControllerAudioDetail.avPlayer?.pause()
            } else if (self.iconChange.currentImage?.isEqual(UIImage(named: "Pause.png")))!{
                ViewControllerAudioDetail.avPlayer?.play()
            }
        }
}


@IBAction func volume(_ sender: UISlider) {

    ViewControllerAudioDetail.avPlayer?.volume = sender.value
}



@IBAction func minusThirtySec(_ sender: Any) {

    let playerCurrentTime = CMTimeGetSeconds((ViewControllerAudioDetail.avPlayer?.currentTime())!)
    var newTime = playerCurrentTime - seekDurationThirty

    if newTime < 0 {
        newTime = 0
    }
    let time2: CMTime = CMTimeMake(Int64(newTime * 1000 as Float64), 1000)
    ViewControllerAudioDetail.avPlayer?.seek(to: time2, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)


}
@IBAction func minusTenSec(_ sender: Any) {

    let playerCurrentTime = CMTimeGetSeconds((ViewControllerAudioDetail.avPlayer?.currentTime())!)
    var newTime = playerCurrentTime - seekDuration

    if newTime < 0 {
        newTime = 0
    }
    let time2: CMTime = CMTimeMake(Int64(newTime * 1000 as Float64), 1000)
    ViewControllerAudioDetail.avPlayer?.seek(to: time2, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

}

@IBAction func plusTenSec(_ sender: Any) {

    guard let duration = ViewControllerAudioDetail.avPlayer?.currentItem?.duration else{
        return
    }
    let playerCurrentTime = CMTimeGetSeconds((ViewControllerAudioDetail.avPlayer?.currentTime())!)
    let newTime = playerCurrentTime + seekDuration

    if newTime < (CMTimeGetSeconds(duration) - seekDuration) {

        let time2: CMTime = CMTimeMake(Int64(newTime * 1000 as Float64), 1000)
        ViewControllerAudioDetail.avPlayer?.seek(to: time2, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

    }

}
@IBAction func plusThirtySec(_ sender: Any) {

    guard let duration = ViewControllerAudioDetail.avPlayer?.currentItem?.duration else{
        return
    }
    let playerCurrentTime = CMTimeGetSeconds((ViewControllerAudioDetail.avPlayer?.currentTime())!)
    let newTime = playerCurrentTime + seekDurationThirty

    if newTime < (CMTimeGetSeconds(duration) - seekDuration) {

        let time2: CMTime = CMTimeMake(Int64(newTime * 1000 as Float64), 1000)
        ViewControllerAudioDetail.avPlayer?.seek(to: time2, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

    }

}

@IBAction func Next(_ sender: Any) {

    ViewControllerAudioDetail.avPlayer?.removeTimeObserver(sliderEndTime)
    ViewControllerAudioDetail.avPlayer?.removeTimeObserver(sliderDurationTime)



    if thisSong == mod.count - 1 {
        thisSong = 0
    } else {
        thisSong += 1
    }


    if thisSong != mod.count{

        name.text = mod[thisSong].AudioName
        player(urlSong:mod[thisSong].UrlName!)

        Status()

    }

}
@IBAction func Back(_ sender: Any) {

    ViewControllerAudioDetail.avPlayer?.removeTimeObserver(sliderEndTime)
    ViewControllerAudioDetail.avPlayer?.removeTimeObserver(sliderDurationTime)



    if thisSong != 0 {
        thisSong -= 1
    } else {
        thisSong = mod.endIndex - 1
    }


        name.text = mod[thisSong].AudioName
        player(urlSong:mod[thisSong].UrlName!)

       Status()




}


func Status(){

    timeSlider = false

    if status == true {
        iconChange.setImage(UIImage(named:"Pause.png"), for: .normal)
        ViewControllerAudioDetail.avPlayer?.play()
    } else {
        iconChange.setImage(UIImage(named:"Play.png"), for: .normal)
        ViewControllerAudioDetail.avPlayer?.pause()
    }

}


@IBAction func Play(_ sender: Any) {


    if ViewControllerAudioDetail.avPlayer?.rate == 0 && status == false{
        status = true
        ViewControllerAudioDetail.avPlayer?.play()
        ViewControllerAudioDetail.avPlayer?.rate = 1.0
        iconChange.setImage(UIImage(named:"Pause.png"), for: .normal)


        if timeSlider == false {

        sliderDurationTime = ViewControllerAudioDetail.avPlayer?.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, 1), queue: nil, using: {
                (CMTime) -> Void in

                self.updateProgressBar()
            })

        }


    } else {

        status = false
        ViewControllerAudioDetail.avPlayer?.rate = 0.0
        ViewControllerAudioDetail.avPlayer?.pause()
        iconChange.setImage(UIImage(named:"Play.png"), for: .normal)

    }

}




func player(urlSong:String) {

    let url = URL(string: urlSong)
    let playerItem = AVPlayerItem(url: url!)
    ViewControllerAudioDetail.avPlayer = AVPlayer(playerItem:playerItem)

    NotificationCenter.default.addObserver(self, selector:#selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)

    sliderDurationTime = ViewControllerAudioDetail.avPlayer?.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, 1), queue: nil, using: {
        (CMTime) -> Void in

        self.updateProgressBar()
    })

     sliderEndTime = ViewControllerAudioDetail.avPlayer!.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC)), queue: DispatchQueue.main) { [weak self] (time) in

        let duration = CMTimeGetSeconds((ViewControllerAudioDetail.avPlayer!.currentItem!.asset.duration))
        self?.sliderSong.value = Float(CMTimeGetSeconds(time)) / Float(duration)

    }


    let duration = CMTimeGetSeconds(ViewControllerAudioDetail.avPlayer!.currentItem!.asset.duration)
    let minutesTextOut = Int(duration) / 60 % 60
    let secondsTextOut = Int(duration) % 60
    let strDuration = String(format:"%02d:%02d", minutesTextOut, secondsTextOut)
    endTime.text = strDuration



}

func playerDidFinishPlaying(note: NSNotification) {

    ViewControllerAudioDetail.avPlayer?.removeTimeObserver(sliderDurationTime)
    ViewControllerAudioDetail.avPlayer?.removeTimeObserver(sliderEndTime)
    NotificationCenter.default.removeObserver(self)


    if thisSong == mod.count - 1 {
        thisSong = 0
    } else {
        thisSong += 1
    }


    if thisSong != mod.count{

        name.text = mod[thisSong].AudioName
        player(urlSong:mod[thisSong].UrlName!)

        Status()

    }




}


func updateProgressBar(){
    let timeNow = Int(ViewControllerAudioDetail.avPlayer!.currentTime().value) / Int(ViewControllerAudioDetail.avPlayer!.currentTime().timescale)

    let minutesText = timeNow / 60
    let secondsText = timeNow % 60

    let duration = String(format:"%02d:%02d", minutesText, secondsText)
    startTime.text = duration

}



override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "toList" {
        let vc = segue.destination as! TableViewControllerAudioList
        vc.mod = mod
    }
}

最佳答案

与其全局声明 AVPlayer,不如将其声明为 ViewControllerAudioDetail 上的静态属性,以防止它被取消初始化(因为这是更好的做法):

static var avPlayer:AVPlayer?

然后您应该根据此 ViewControllerAudioDetail.avPlayer 的状态恢复播放器 View 组件的状态。可以根据information given here判断是否播放例如,可以使用 ViewControllerAudioDetail.avPlayer.currentTime() 找出当前时间。

关于ios - Avplayer 被创建了 2 次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45007017/

相关文章:

ios - View 模型可以监听其自身属性的变化吗?

ios - 尝试根据我使用 prepareforsegue 单击的按钮隐藏 View

ios - 我无法快速从本地服务器加载视频文件

ios - 如何在初始化 AVURLAsset 时根据 AVURLAssetHTTPCookiesKey 设置正确的 cookie 值

ios - 从 plist 中检索后无法释放对象

ios - XCode 代码设计问题

ios - 以编程方式自动连接到 WiFi iOS

SwiftUI:如何让 TextField 成为第一响应者?

ios - 使用 ObjectMapper - 如何将 JSON 结果快速转换为 TableView

iOS AVPlayer 在播放图标上显示带有十字线的屏幕