индекс находится вне диапазона после фильтрации массива

#swift

#swift

Вопрос:

Я пытаюсь отфильтровать массив песен, чтобы в нем были только песни, в которых имя исполнителя песни совпадает с именем исполнителя (которое всегда является выбранным исполнителем). Когда я запускаю свое приложение, оно выдает фатальную ошибку: индекс вне диапазона, хотя в моей консоли отладки artistSongs есть 4 элемента. Я не понимаю, как я получаю этот сбой.

  override func viewDidLoad() {
    super.viewDidLoad()
    
    retriveData()
    
    //Register nib
    topSongTableView.register(TopSongTableViewCell.nib(), forCellReuseIdentifier: TopSongTableViewCell.topSongCell)
    
    ArtistPicture.image = artistCover
    ArtistLabel.text = ArtistName
    
    
    //Assign TableView to self
    topSongTableView.delegate = self
    topSongTableView.dataSource = self
}
//Define number of rows in topSongsTableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 5
}

// songs of artist
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TopSongTableViewCell", for: indexPath) as! TopSongTableViewCell
    let artistSongs = songs.filter{ $0.artistName == ArtistName }
    print(artistSongs)
    cell.TopSongLabel.text = artistSongs[indexPath.row].cleanName //CASH
    cell.SongImage.image = UIImage(named: artistSongs[indexPath.row].cover)
    return cell
}
  

Комментарии:

1. $ 0.artistName == artistName , какой тип artistName? а имя исполнителя — это класс?

2. @luffy_064 Имя исполнителя — это переменная строка, которая заполняется, когда пользователь выбирает исполнителя из другого табличного представления. Смысл этого в том, чтобы иметь только песни с этим именем исполнителя.

3. вы никогда не должны выполнять фильтр внутри cellForRow. Переместите свой метод фильтрации в viewDidLoad или любой другой метод.

Ответ №1:

Ваша проблема в том, что ваш TableView topSongTableView ожидает отображения 5 строк (вы это жестко запрограммировали), но когда вы удаляете свои ячейки из очереди, вы также фильтруете artistSongs одновременно (это не должно быть сделано здесь), и это создает в вашем случае массив с менее чем 5 элементами (4 в вашем случае).

Итак, здесь func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell вы пытаетесь удалить из очереди больше ячеек, чем элементов artistSongs .

Допустим let artistSongs = songs.filter{ $0.artistName == ArtistName } , создается массив только из 3 элементов, но ваше табличное представление ожидает 5, когда вы отменяете очередь своих ячеек и пытаетесь получить доступ к песне artistSongs[indexPath.row] , она будет работать для первых 3 строк, а затем произойдет сбой (ваш текущий сбой).

Ваше решение — отфильтровать песни исполнителя где-нибудь в другом месте, скажем, в viewDidLoad , а затем использовать этот массив для безопасного заполнения вашего табличного представления:

 // ADD THIS
var filteredSongs: [Song]()

override func viewDidLoad() {
    super.viewDidLoad()
    
    [...]

    // ADD THIS
    self.filteredSongs = songs.filter{ $0.artistName == ArtistName }
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // CHANGE THIS
    return self.filteredSongs.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TopSongTableViewCell", for: indexPath) as! TopSongTableViewCell
    // REMOVE THIS
    //let artistSongs = songs.filter{ $0.artistName == ArtistName }
    // REMOVE THIS
    //print(artistSongs)
    cell.TopSongLabel.text = self.filteredSongs[indexPath.row].cleanName
    cell.SongImage.image = UIImage(named: self.filteredSongs[indexPath.row].cover)
    return cell
}
  

Комментарии:

1. Я уверен, что ваше решение правильное, но похоже, что вы объявляете новый массив var artistSongs: [ArtistSong]() . Мне все еще нужны данные из songs массива, чтобы отображаться в моем табличном представлении.

2. Я получаю эту ошибку в self.artistSong строке, не удается присвоить значение типа ‘[Песни]’ типу ‘[Строка]’

3. Я обновил пример и переименовал artistSongs в filteredSongs, чтобы быть более понятным. Насколько я понимаю, у вас есть массив песен где-то в вашем контроллере представления, и вы хотите отфильтровать этот массив благодаря artistName , а затем отобразить эти отфильтрованные песни в вашем табличном представлении — вот почему я объявил новый массив, который может безопасно использоваться в вашем табличном представлении.

4. var filteredSongs: [Song]() решена моя проблема в предыдущем комментарии. Спасибо! Особенно для указания на то, что я должен фильтровать свой массив в viewDidLoad.