What is the reason of an index to be out of range and how to fix this issue in my code?

Vugar

This is audio player, It worked fine before I started to try stream audios from firebase. Now data is downloaded from the firebase database, the image, title and subtitle are being displayed correctly, but when user taps on the cell the audio doesn't play and it throws a fatal error, Thread 1: Fatal error: Index out of range

The ScreenShot Of ListOfAudioLessonsTableViewController Data is successfully downloaded from firebase. Fatal Error screenshot Fatal error Log

This is a table view controller which lists the audio tracks from firebase database.

import UIKit
import AVKit
import AVFoundation
import FirebaseFirestore
import Combine
import SDWebImage

class ListOfAudioLessonsTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet var table: UITableView!
        
    let placeHolderImage = UIImage(named: "placeHolderImage")
    
    private var cancellable: AnyCancellable?
    private var viewModel = AudiosViewModel()
    var paragraphs = [Audio]()
    


        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.viewModel.fetchData()
            self.title = "Audio Lessons"
                       
            table.delegate = self
            table.dataSource = self
            
            cancellable = viewModel.$audios.sink { _ in
                DispatchQueue.main.async{
                    
                    self.table.reloadData()
        }
    }            // Do any additional setup after loading the view.
}

        
        
        // Table
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            print("audios count = ", viewModel.audios.count)
            return viewModel.audios.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
            let audio = viewModel.audios[indexPath.row]
            tableView.tableFooterView = UIView()
            cell.textLabel?.text = audio.albumName
            cell.detailTextLabel?.text = audio.name
            cell.accessoryType = .disclosureIndicator
            
            
            let imageURL = audio.audioImageName
                    cell.imageView?.sd_imageIndicator = SDWebImageActivityIndicator.gray
            cell.imageView?.sd_setImage(with: URL(string: imageURL),
                                        placeholderImage: placeHolderImage,
                                        options: SDWebImageOptions.highPriority,
                                        context: nil,
                                        progress: nil,
            completed: { downloadedImage, downloadException, cacheType, downloadURL in
                if let downloadException = downloadException {
                    print("error downloading the image: \(downloadException.localizedDescription)")
                } else {
                    print("successfuly downloaded the image: \(String(describing: downloadURL?.absoluteString))")
    }
})
            
            cell.textLabel?.numberOfLines = 0
            cell.detailTextLabel?.numberOfLines = 0
            let backgroundView = UIView()
            backgroundView.backgroundColor = UIColor(named: "AudioLessonsCellHighlighted")
            cell.selectedBackgroundView = backgroundView
            cell.textLabel?.font = UIFont(name: "Helvetica-Bold", size: 14)
            cell.detailTextLabel?.font = UIFont(name: "Helvetica", size: 12)
        
            return cell
}
    
        
        
        
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 100
            
        }
        
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
      
            // present the player
            let position = indexPath.row
            
            //lessons
            
            guard let vc = storyboard?.instantiateViewController(identifier: "AudioPlayer") as? AudioPlayerViewController else {
            return
            
        }
            
            vc.paragraphs = paragraphs
            vc.position = position
            
        present(vc, animated: true)

    }
    
     func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) {
            cell.contentView.backgroundColor = UIColor(named: "AudioLessonsHighlighted")
            cell.textLabel?.highlightedTextColor = UIColor(named: "textHighlighted")
            cell.detailTextLabel?.highlightedTextColor = UIColor(named: "textHighlighted")
           

        }
    }
    
     func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) {
            cell.contentView.backgroundColor = nil
            
        }
    }
}
import UIKit
import AVFoundation
import MediaPlayer
import AVKit

class AudioPlayerViewController: UIViewController {
                
public var position: Int = 0
    public var paragraphs: [Audio] = []
   
@IBOutlet var holder: UIView!
var player: AVPlayer?
    var playerItem: AVPlayerItem?
    var isSeekInProgress = false
    var chaseTime = CMTime.zero
    fileprivate let seekDuration: Float64 = 15
    var playerCurrentItemStatus: AVPlayerItem.Status = .unknown

                // User Interface elements
private let albumImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
return imageView
}()
    
private let paragraphNumberLabel: UILabel = {
let label = UILabel()
label.textAlignment = .left
label.font = .systemFont(ofSize: 16, weight: .light)
label.numberOfLines = 0 // allow line wrap
label.textColor = UIColor(named: "PlayerColors")
return label
}()
                
private let albumNameLabel: UILabel = {
let label = UILabel()
label.textAlignment = .left
label.font = .systemFont(ofSize: 18, weight: .bold)
label.numberOfLines = 0 // allow line wrap
label.textColor = UIColor(named: "PlayerColors")
return label
}()
                
private let songNameLabel: UILabel = {
let label = UILabel()
label.textAlignment = .left
    label.font = .systemFont(ofSize: 16, weight: .ultraLight)
label.numberOfLines = 0 // allow line wrap
label.textColor = UIColor(named: "PlayerColors")
return label
}()
    
private let elapsedTimeLabel: UILabel = {
let label = UILabel()
label.textAlignment = .left
label.font = .systemFont(ofSize: 12, weight: .light)
label.textColor = UIColor(named: "PlayerColors")
label.text = "00:00"
label.numberOfLines = 0
return label
}()
        
private let remainingTimeLabel: UILabel = {
let label = UILabel()
label.textAlignment = .left
label.font = .systemFont(ofSize: 12, weight: .light)
label.textColor = UIColor(named: "PlayerColors")
label.text = "00:00"
label.numberOfLines = 0
return label
}()
        
private let playbackSlider: UISlider = {
let v = UISlider()
    v.addTarget(AudioPlayerViewController.self, action: #selector(progressScrubbed(_:)), for: .valueChanged)
    v.minimumTrackTintColor = UIColor.lightGray
v.maximumTrackTintColor = UIColor.darkGray
v.thumbTintColor = UIColor(named: "PlayerColors")
v.minimumValue = 0
v.isContinuous = true
return v
}()
   
    
    

let playPauseButton = UIButton()
    
    
                

override func viewDidLoad() {
    super.viewDidLoad()
                    
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGesture(gesture:)))
    self.playbackSlider.addGestureRecognizer(panGesture)
                    

let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(AVAudioSession.Category.playback)
            }
                catch{
                        print(error)
                    }
                }
                
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        
                
if holder.subviews.count == 0 {
    configure()
                    }
                }
                func configure() {
                    // set up player
                    let song = paragraphs[position]
                    
                    let url = URL(string: song.trackURL)
                    let playerItem: AVPlayerItem = AVPlayerItem(url: url!)
                    do {
                        try AVAudioSession.sharedInstance().setMode(.default)
                        try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
                        guard url != nil else {
                            print("urls string is nil")
                            return
                        }
   
                        player = AVPlayer(playerItem: playerItem)
                        
                        
                        let duration : CMTime = playerItem.asset.duration
                        
                        let seconds : Float64 = CMTimeGetSeconds(duration)
                        
                        remainingTimeLabel.text = self.stringFromTimeInterval(interval: seconds)
                        
                        let currentDuration : CMTime = playerItem.currentTime()
                        
                        let currentSeconds : Float64 = CMTimeGetSeconds(currentDuration)
                        
                        elapsedTimeLabel.text = self.stringFromTimeInterval(interval: currentSeconds)

                        playbackSlider.maximumValue = Float(seconds)
                       
                        
                        player!.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, preferredTimescale: 1), queue: DispatchQueue.main) { (CMTime) -> Void in
                            
                            if self.player!.currentItem?.status == .readyToPlay {
                                let time : Float64 = CMTimeGetSeconds(self.player!.currentTime());
                                self.playbackSlider.value = Float(time)
                                
                                self.elapsedTimeLabel.text = self.stringFromTimeInterval(interval: time)
                            }
                            
                            let playbackLikelyToKeepUp = self.player?.currentItem?.isPlaybackLikelyToKeepUp
                            if playbackLikelyToKeepUp == false{
                                print("IsBuffering")
                                self.playPauseButton.isHidden = true
                               
                            } else {
                                // stop the activity indicator
                                print("Buffering completed")
                                
                                self.playPauseButton.isHidden = false
                                
                            }
                        }
                        
                        
                        playbackSlider.addTarget(self, action: #selector(AudioPlayerViewController.progressScrubbed(_:)), for: .valueChanged)
                        self.view.addSubview(playbackSlider)
                        //subroutine used to keep track of current location of time in audio file
                        guard let player = player else {
                            print("player is nil")
                            return
                        }
                        player.play()
                        
                    }
                    catch {
                        print("error accured")
                    }
                    // set up user interface elements
                    
                    //album cover
albumImageView.frame = CGRect(x: 20,
                              y: 20,
                              width: holder.frame.size.width - 40,
                              height: holder.frame.size.width - 40)
                    
albumImageView.image = UIImage(named: song.audioImageName)
                    holder.addSubview(albumImageView)
                    
                    //Labels Song name, album, artist
                    albumNameLabel.frame = CGRect(x: 20,
                                                 y: holder.frame.size.height - 300,
                                                  width: holder.frame.size.width - 40,
                                                  height: 20)
                    paragraphNumberLabel.frame = CGRect(x: 20,
                                                  y: holder.frame.size.height - 280,
                                                  width: holder.frame.size.width-40,
                                                  height: 20)
                    songNameLabel.frame = CGRect(x: 20,
                                                  y: holder.frame.size.height - 260,
                                                  width: holder.frame.size.width-40,
                                                  height: 20)
                    playbackSlider.frame = CGRect(x: 20,
                                                  y: holder.frame.size.height - 235,
                                                  width: holder.frame.size.width-40,
                                                  height: 40)
                    elapsedTimeLabel.frame = CGRect(x: 25,
                                                    y: holder.frame.size.height - 200,
                                                    width: holder.frame.size.width-40,
                                                    height: 15)
                    remainingTimeLabel.frame = CGRect(x: holder.frame.size.width-60,
                                                      y: holder.frame.size.height - 200,
                                                      width: holder.frame.size.width-20,
                                                      height: 15)
                    songNameLabel.text = song.name
                    albumNameLabel.text = song.albumName
                    paragraphNumberLabel.text = song.paragraphNumber
                    holder.addSubview(songNameLabel)
                    holder.addSubview(albumNameLabel)
                    holder.addSubview(paragraphNumberLabel)
                    holder.addSubview(elapsedTimeLabel)
                    holder.addSubview(remainingTimeLabel)
                    //Player controls
                    let nextButton = UIButton()
                    let backButton = UIButton()
                    let seekForwardButton = UIButton()
                    let seekBackwardButton = UIButton()
                    //frames of buttons
                    playPauseButton.frame = CGRect(x: (holder.frame.size.width - 40) / 2.0,
                                                   y: holder.frame.size.height - 172.5,
                                                   width: 40,
                                                   height: 40)
                    
                    nextButton.frame = CGRect(x: holder.frame.size.width - 70,
                                                   y: holder.frame.size.height - 162.5,
                                                   width: 30,
                                                   height: 20)
                    
                    backButton.frame = CGRect(x: 70 - 30,
                                            y: holder.frame.size.height - 162.5,
                                            width: 30,
                                            height: 20)
                    seekForwardButton.frame = CGRect(x: holder.frame.size.width - 140,
                                                     y: holder.frame.size.height - 167.5,
                                            width: 30,
                                            height: 30)
                    seekBackwardButton.frame = CGRect(x: 110,
                                            y: holder.frame.size.height - 167.5,
                                            width: 30,
                                            height: 30)
                    let volumeView = MPVolumeView(frame: CGRect(x: 20,
                                                                y: holder.frame.size.height - 80,
                                                                width: holder.frame.size.width-40,
                                                                height: 30))
                    holder.addSubview(volumeView)
                    //actions of buttons
                    playPauseButton.addTarget(self, action: #selector(didTapPlayPauseButton), for: .touchUpInside)
                    backButton.addTarget(self, action: #selector(didTapBackButton), for: .touchUpInside)
                    nextButton.addTarget(self, action: #selector(didTapNextButton), for: .touchUpInside)
                    seekForwardButton.addTarget(self, action: #selector(seekForwardButtonTapped), for: .touchUpInside)
                    seekBackwardButton.addTarget(self, action: #selector(seekBackwardButtonTapped), for: .touchUpInside)
                    //styling of buttons
                    playPauseButton.setBackgroundImage(UIImage(systemName: "pause.fill"), for: .normal)
                    nextButton.setBackgroundImage(UIImage(systemName: "forward.fill"), for: .normal)
                    backButton.setBackgroundImage(UIImage(systemName: "backward.fill"), for: .normal)
                    seekForwardButton.setBackgroundImage(UIImage(systemName: "goforward.15"), for: .normal)
                    seekBackwardButton.setBackgroundImage(UIImage(systemName: "gobackward.15"), for: .normal)
   
                    playPauseButton.tintColor = UIColor(named: "PlayerColors")
                    nextButton.tintColor = UIColor(named: "PlayerColors")
                    backButton.tintColor = UIColor(named: "PlayerColors")
                    seekForwardButton.tintColor = UIColor(named: "PlayerColors")
                    seekBackwardButton.tintColor = UIColor(named: "PlayerColors")
                    
                    holder.addSubview(playPauseButton)
                    holder.addSubview(nextButton)
                    holder.addSubview(backButton)
                    holder.addSubview(seekForwardButton)
                    holder.addSubview(seekBackwardButton)
}
    
    @objc func panGesture(gesture: UIPanGestureRecognizer) {
        let currentPoint = gesture.location(in: playbackSlider)
        let percentage = currentPoint.x/playbackSlider.bounds.size.width;
        let delta = Float(percentage) * (playbackSlider.maximumValue - playbackSlider.minimumValue)
        let value = playbackSlider.minimumValue + delta
        playbackSlider.setValue(value, animated: true)
    }
    
    @objc func progressScrubbed(_ playbackSlider: UISlider!) {
        let seconds : Int64 = Int64(playbackSlider.value)
        let targetTime:CMTime = CMTimeMake(value: seconds, timescale: 1)
        player!.seek(to: targetTime)
        if player!.rate == 0
        {
            player?.play()
        }
    }
    
    func setupNowPlaying() {
      // Define Now Playing Info
      var nowPlayingInfo = [String : Any]()
      nowPlayingInfo[MPMediaItemPropertyTitle] = "Unstoppable"
      
      if let image = UIImage(named: "artist") {
        nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { size in
          return image
        }
      }
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player?.currentTime
        nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = playerItem?.duration
        nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player?.rate
      
      // Set the metadata
      MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
    
    func updateNowPlaying(isPause: Bool) {
      // Define Now Playing Info
      var nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo!
      
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player?.currentTime
      nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = isPause ? 0 : 1
      
      // Set the metadata
      MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
    
    func setupNotifications() {
      let notificationCenter = NotificationCenter.default
      notificationCenter.addObserver(self,
                                     selector: #selector(handleInterruption),
                                     name: AVAudioSession.interruptionNotification,
                                     object: nil)
      notificationCenter.addObserver(self,
                                     selector: #selector(handleRouteChange),
                                     name: AVAudioSession.routeChangeNotification,
                                     object: nil)
    }

    @objc func handleRouteChange(notification: Notification) {
      guard let userInfo = notification.userInfo,
        let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
        let reason = AVAudioSession.RouteChangeReason(rawValue:reasonValue) else {
          return
      }
      switch reason {
      case .newDeviceAvailable:
        let session = AVAudioSession.sharedInstance()
        for output in session.currentRoute.outputs where output.portType == AVAudioSession.Port.headphones {
          print("headphones connected")
          DispatchQueue.main.sync {
            player?.play()
          }
          break
        }
      case .oldDeviceUnavailable:
        if let previousRoute =
          userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
          for output in previousRoute.outputs where output.portType == AVAudioSession.Port.headphones {
            print("headphones disconnected")
            DispatchQueue.main.sync {
                player?.pause()
            }
            break
          }
        }
      default: ()
      }
    }
    
    @objc func handleInterruption(notification: Notification) {
      guard let userInfo = notification.userInfo,
        let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
        let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
          return
      }
      
      if type == .began {
        print("Interruption began")
        // Interruption began, take appropriate actions
      }
      else if type == .ended {
        if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
          let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
          if options.contains(.shouldResume) {
            // Interruption Ended - playback should resume
            print("Interruption Ended - playback should resume")
            player?.play()
          } else {
            // Interruption Ended - playback should NOT resume
            print("Interruption Ended - playback should NOT resume")
          }
        }
      }
    }
    
    @objc func didTapPlayPauseButton() {
        if player?.timeControlStatus == .playing {
                           //pause
                           player?.pause()
                           
                           
                           //show play button
                           playPauseButton.setBackgroundImage(UIImage(systemName: "play.fill"), for: .normal)
                           //shrink image
                           UIView.animate(withDuration: 0.2, animations: {
                               self.albumImageView.frame = CGRect(x: 50,
                                                             y: 50,
                                                             width: self.holder.frame.size.width - 100,
                                                             height: self.holder.frame.size.width - 100)
                               
                           })
                           
                       }
                       else {
                           //play
                           player?.play()
                           //show pause button
                           playPauseButton.setBackgroundImage(UIImage(systemName: "pause.fill"), for: .normal)
                           
                           //increase image size
                           UIView.animate(withDuration: 0.4, animations: {
                               self.albumImageView.frame = CGRect(x: 20,
                                                             y: 20,
                                                             width: self.holder.frame.size.width - 40,
                                                             height: self.holder.frame.size.width - 40)
                               
                           })
                           
                           
                   }
                           
                       
                   }

    private func setupView() {
        setupConstraints()
    }
    

  
                       
}
   
    
   
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        player?.play()
        UIApplication.shared.isIdleTimerDisabled = true
    }
        
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        player?.pause()
        UIApplication.shared.isIdleTimerDisabled = false
        
    }
    
}

AudioViewModel

import Foundation
import FirebaseFirestore


class AudiosViewModel: ObservableObject {

@Published var audios = [Audio]()
private var db = Firestore.firestore()


func fetchData() {
    db.collection("audios").addSnapshotListener { [self] (querySnapshot, error) in
    guard let documents = querySnapshot?.documents else {
    print("No Documents")
    return
}

self.audios = documents.map { (queryDocumentSnapshot) -> Audio in
    let data = queryDocumentSnapshot.data()
                
    let name = data["name"] as? String ?? ""
    let albumName = data["albumName"] as? String ?? ""
    let audioImageName = data["audioImageName"] as? String ?? ""
    let paragraphNumber  = data["paragraphNumber"] as? String ?? ""
    let trackURL  = data["trackURL"] as? String ?? ""
              
    print(data)

    
    return Audio(name: name, albumName: albumName, paragraphNumber: paragraphNumber, audioImageName: audioImageName, trackURL: trackURL)
              
            }
        }
    }
}

Audio Structure

import Foundation

struct Audio {
    let name: String
    let albumName: String
    let paragraphNumber: String
    let audioImageName: String
    let trackURL: String
}

RAHUL NIMJE

Assign/append value to your paragraphs and also check your position if there will be no values/wrong position it'll throw index out of range

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to fix "IndexError: List index is out of range" in my code?

how can I fix this error in this code? index out of range

How to Fix "List Index out of range" in python?

How to fix this list index out of range error

How to fix "IndexError: list index out of range"

How to fix 'String index out of range' error

How to fix list list index out of range

How to fix list index out of range?

How to fix Index out of range in python

How to fix the error "index out of range"

How to fix : "list index out of range ..." in Python?

how to fix tuple error, index out of range

How do I fix index out of range when index is in range

How to fix an issue in my javascript slider range?

How to fix web scraping Python code "IndexError: list index out of range" when the code hits missing values

the code show bad input and index out of range on the lines, how can i fix it

Can't figure out how to fix "list index out of range"

What's wrong with my code? IndexError: list assignment index out of range

How to solve Index out of range for complex code

TableView Index out of range issue

list index out of range Error Pygame How To Fix?

How to fix "IndexError: tuple index out of range" in python?

How to fix IndexError: String index out of range - Python

how to fix an index out of range error and instead print a statement

How to fix 'list index out of range' error in ZigZag problem?

How do you fix 'IndexError: list index out of range' in Python

How to fix "IndexError: list index out of range" in Tensorflow

How to fix "IndexError: list index out of range" in Python?

How to fix this "IndexError: list index out of range" in snakemake