В настоящее время я пытаюсь воспроизвести аудио из базы данных Firebase. У меня есть два контроллера представления, первый - контроллер табличного представления, и второй - контроллер представления с AVAudioPlayer. Я пытаюсь выяснить, как успешно воспроизводить аудио-URL, который захватывается из firebase, который затем передается на второй контроллер представления для воспроизведения, когда аудио выбирается в табличном представлении. Вот мой текущий код, который возвращает «Неустранимая ошибка: неожиданно обнаружил ноль при развертывании необязательного значения» на моем втором контроллере просмотра, когда звук выбирается из контроллера табличного просмотра.
TableViewController:
import UIKit
import Firebase
class HeaderViewTableViewController: UITableViewController {
@IBOutlet weak var trackImage: UIImageView!
@IBOutlet weak var trackName: UILabel!
@IBOutlet weak var artistName: UILabel!
@IBOutlet weak var trackHeaderImage: UIImageView!
var image: UIImageView?
var image2: UIImageView?
var songs = [String]()
var urls = [URL]()
var song:SongPost?
private let tableHeaderViewHeight: CGFloat = 350.0
private let tableHeaderViewCutAway: CGFloat = 0.1
var headerView: HeaderView!
var headerMaskLayer: CAShapeLayer!
override func viewDidLoad() {
super.viewDidLoad()
print(song)
trackName.text = song?.title
ImageService.getImage(withURL: song!.coverImage) { image in
self.trackImage.image = image
self.trackHeaderImage.image = image
}
artistName.text = song?.author.fullname
tableView.tableFooterView = UIView()
headerView = tableView.tableHeaderView as! HeaderView
headerView.imageView = trackImage
tableView.tableHeaderView = nil
tableView.addSubview(headerView)
tableView.contentInset = UIEdgeInsets(top: tableHeaderViewHeight, left: 0, bottom: 0, right: 0)
tableView.contentOffset = CGPoint(x: 0, y: -tableHeaderViewHeight + 64)
//cut away header view
headerMaskLayer = CAShapeLayer()
headerMaskLayer.fillColor = UIColor.black.cgColor
headerView.layer.mask = headerMaskLayer
let effectiveHeight = tableHeaderViewHeight - tableHeaderViewCutAway/2
tableView.contentInset = UIEdgeInsets(top: effectiveHeight, left: 0, bottom: 0, right: 0)
tableView.contentOffset = CGPoint(x: 0, y: -effectiveHeight)
updateHeaderView()
}
func updateHeaderView() {
let effectiveHeight = tableHeaderViewHeight - tableHeaderViewCutAway/2
var headerRect = CGRect(x: 0, y: -effectiveHeight, width: tableView.bounds.width, height: tableHeaderViewHeight)
if tableView.contentOffset.y < -effectiveHeight {
headerRect.origin.y = tableView.contentOffset.y
headerRect.size.height = -tableView.contentOffset.y + tableHeaderViewCutAway/2
}
headerView.frame = headerRect
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y:0))
path.addLine(to: CGPoint(x: headerRect.width, y: 0))
path.addLine(to: CGPoint(x: headerRect.width, y: headerRect.height))
path.addLine(to: CGPoint(x: 0, y: headerRect.height - tableHeaderViewCutAway))
headerMaskLayer?.path = path.cgPath
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
self.tableView.decelerationRate = UIScrollView.DecelerationRate.fast
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
@IBAction func backButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
extension HeaderViewTableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (song?.audioName.count)!
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SongCell", for: indexPath) as! SongNameTableViewCell
cell.set(song: self.song!)
cell.songName.text = song?.audioName[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(identifier: "ViewController2") as? ViewController2
vc?.song = song
vc?.audioName = (song?.audioName[indexPath.row])!
self.present(vc!, animated: true, completion: nil)
vc?.url = song?.audioUrl[indexPath.row]
}
}
extension HeaderViewTableViewController {
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
updateHeaderView()
}
}
Второй ViewController:
import UIKit
import AVFoundation
import MediaPlayer
import Firebase
class ViewController2: UIViewController, UITabBarControllerDelegate {
var song2 = [SongPost]()
var song: SongPost?
var audioName : String?
var url:URL?
@IBOutlet weak var progressBar: UISlider!
@IBOutlet weak var downChevron: UIButton!
var timer:Timer?
var player = AVAudioPlayer()
@IBOutlet weak var currentTime: UILabel!
@IBOutlet weak var durationTime: UILabel!
@IBOutlet weak var coverImage: UIImageView!
@IBOutlet weak var backgroundImage: UIImageView!
@IBOutlet weak var songName: UILabel!
@IBOutlet weak var artistName: UILabel!
var trackID: Int = 0
var toggleState = 1
var ref: DatabaseReference?
@IBOutlet weak var playButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
setUI()
tabBarController?.tabBar.barTintColor = UIColor.black
tabBarController?.tabBar.isTranslucent = false
tabBarController?.tabBar.tintColor = .white
tabBarController?.tabBar.unselectedItemTintColor = .gray
do {
let songURL = url
print(songURL)
try player = AVAudioPlayer(contentsOf: songURL!)
progressBar.maximumValue = Float(player.duration)
timer = Timer.scheduledTimer(timeInterval: 0.00001, target: self, selector: #selector(changeSliderValueFollowPlayerCurtime), userInfo: nil, repeats: true)
player.delegate = self
player.play()
MPNowPlayingInfoCenter.default().nowPlayingInfo = [
MPMediaItemPropertyTitle : "The Box",
MPMediaItemPropertyArtist: "Roddy Ricch",
MPMediaItemPropertyPlaybackDuration: player.duration,
]
UIApplication.shared.beginReceivingRemoteControlEvents()
becomeFirstResponder()
} catch {
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: .defaultToSpeaker)
} catch {
}
}
func setUI() {
ImageService.getImage(withURL: song!.coverImage) { image in
self.coverImage.image = image
self.backgroundImage.image = image
}
songName.text = song?.title
artistName.text = song?.author.fullname
}
override func remoteControlReceived(with event: UIEvent?) {
if let event = event {
if event.type == .remoteControl {
switch event.subtype {
case .remoteControlPlay:
player.play()
case .remoteControlPause:
player.pause()
case .remoteControlNextTrack:
print("next")
case .remoteControlPreviousTrack:
print("previous")
default:
print("error")
}
}
}
}
@objc func changeSliderValueFollowPlayerCurtime() {
let curValue = Float(player.currentTime)
progressBar.value = curValue
}
@IBAction func sliderUsed(_ sender: Any) {
player.pause()
let curTime = progressBar.value
player.currentTime = TimeInterval(curTime)
player.play()
}
@IBAction func playPauseButtonTapped(_ sender: Any) {
let playBtn = sender as! UIButton
if toggleState == 1 {
player.pause()
toggleState = 2
playBtn.setImage(UIImage(named:"play 5.png"),for:UIControl.State.normal)
} else {
player.play()
toggleState = 1
playBtn.setImage(UIImage(named:"pause 4.png"),for:UIControl.State.normal)
}
}
@IBAction func nextButton(_ sender: Any) {
}
@IBAction func backButton(_ sender: Any) {
if trackID != 0 || trackID > 0 {
trackID -= 1
}
do {
let audioPath = Bundle.main.path(forResource: "the box", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
} catch {
}
}
@IBAction func downChevronTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
extension ViewController2: AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if flag {
do {
let audioPath = Bundle.main.path(forResource: "the box", ofType: "mp3")
try self.player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
progressBar.maximumValue = Float(player.duration)
timer = Timer.scheduledTimer(timeInterval: 0.00001, target: self, selector: #selector(changeSliderValueFollowPlayerCurtime), userInfo: nil, repeats: true)
player.delegate = self
player.play()
} catch {
}
}
}
}
SongPost Класс:
import Foundation
class SongPost {
var id: String
var author: UserProfile
var title: String
var coverImage: URL
var audioUrl: [URL]
var audioName : [String]
var createdAt:Date
init(id:String, author:UserProfile, title:String, coverImage:URL, audioUrl:[URL], audioName: [String] ,timestamp:Double) {
self.id = id
self.author = author
self.coverImage = coverImage
self.audioUrl = audioUrl
self.audioName = audioName
self.title = title
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
}
ОБНОВЛЕНО
Fun c Настройка кода:
func configure(song: SongPost, audioName: String, url:URL) {
do {
let songURL = url
print(songURL)
// let audioPath = Bundle.main.path(forResource: "the box", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: songURL)
progressBar.maximumValue = Float(player.duration)
timer = Timer.scheduledTimer(timeInterval: 0.00001, target: self, selector: #selector(changeSliderValueFollowPlayerCurtime), userInfo: nil, repeats: true)
player.delegate = self
player.play()
MPNowPlayingInfoCenter.default().nowPlayingInfo = [
MPMediaItemPropertyTitle : "The Box",
MPMediaItemPropertyArtist: "Roddy Ricch",
MPMediaItemPropertyPlaybackDuration: player.duration,
]
UIApplication.shared.beginReceivingRemoteControlEvents()
becomeFirstResponder()
} catch {
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: .defaultToSpeaker)
} catch {
}
}