#ios #json #swift #uitableview #parsing
Вопрос:
У меня есть локальный файл JSON с некоторыми данными. Нужно знать, как загрузить аудио из локального JSON и загрузить его на кнопку в табличном представлении. Мой JSON:
{
"beatPack":
{
"loops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop",
"imagename": "beatpackone"
"songName": "alien.mp3"
}
]
}
}
Таким образом, он должен отображать каждую песню на кнопке в табличном представлении. Вот мои методы песни, они могут отображать песню в каждой строке, но не из JSON и не в правильной нумерации, которая мне нужна:
func playLoop(songName: String) {
let url = Bundle.main.url(forResource: songName, withExtension: ".mp3") // you should check it for errors
audioPlayer = try! AVAudioPlayer(contentsOf: url!) // of course you should catch the error and deal with it...
audioPlayer.play()
print(songName)
}
func gettingSongName() {
let folderURL = URL(fileURLWithPath: Bundle.main.resourcePath!)
do {
let songPath = try FileManager.default.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for song in songPath {
var mySong = song.absoluteString
if mySong.contains(".mp3") {
let findString = mySong.components(separatedBy: "/")
mySong = findString[findString.count - 1]
mySong = mySong.replacingOccurrences(of: " ", with: " ")
mySong = mySong.replacingOccurrences(of: ".mp3", with: "")
songs.append(mySong)
}
}
} catch {
}
}
Вот мой вид таблицы:
extension BPLibraryViewController: UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 180
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return loopsName.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: S.newOneCell, for: indexPath) as! BeatPackLibraryCell
let loopsCount = loopsName[indexPath.row] //Instance of our arrays from JSON
cell.loopNameLabel.text = loopsCount.name
cell.producerNameLabel.text = loopsCount.producer
cell.loopsCountLabel.text = String(loopsName.count)
cell.genreLabel.text = loopsCount.genre
cell.firstBeatButtonLabel.setImage(UIImage(named: loopsCount.imagename), for: .normal)
cell.delegate = self
cell.selectionStyle = .none
cell.tag = indexPath.row
if let playingCell = currentPlayingIndex, playingCell == indexPath.row {
cell.firstBtnOutlet.setImage(UIImage(named: "pauseButtonPack.png"), for:
.normal)
} else {
cell.firstBtnOutlet.setImage(UIImage(named: "playButtonPack.png"), for:
.normal)
}
return cell
}
Кнопка, которая воспроизводит песню в каждом ряду:
extension BPLibraryViewController: BeatPackLibraryDelegate {
func didTapFirstSong(cell: BeatPackLibraryCell) {
let indexPath = self.tableView.indexPath(for: cell)
if currentPlayingIndex == cell.tag {
audioPlayer.pause()
currentPlayingIndex = nil
} else { //IF PAUSE BUTTON
playLoop(songName: songs[cell.tag])
currentPlayingIndex = cell.tag
}
tableView.reloadData()
print("Done")
}
Итак, как загрузить песни из локального файла JSON и отобразить их в каждой строке.
Комментарии:
1. Неясно, о чем вы спрашиваете, есть ли у вас mp3-файлы в вашем основном пакете или нет, и если да, то почему вы не можете получить к ним доступ?
2. Да, но главная проблема заключается в том, как правильно получить доступ к ним в табличном представлении, чтобы они отображались в каждой строке?
3. Что означает отображение песни в каждой строке ?
4. Моя ошибка, я отредактировал, он должен воспроизводить песню в каждом ряду. Проверьте скриншот, у нас есть инопланетянин, и он должен воспроизводить «песню инопланетян». Так как же я могу это сделать?
Ответ №1:
Во-первых, метод playLoop
не может работать, потому что расширение файла в withExtension
параметре должно быть указано без точки.
Мое предложение состоит в том, чтобы добавить вычисляемое свойство в Loop
структуру, чтобы, например, получить URL-адрес в пакете приложений
struct Loop : Decodable {
let name, producer, count, genre, imagename, songName : String
private enum CodingKeys : String, CodingKey { case name, producer, count, genre, imagename, songName }
var songURL : URL {
let components = songName.components(separatedBy: ".")
guard components.count == 2,
let url = Bundle.main.url(forResource: components[0], withExtension: components[1]) else { fatalError("Audio file is missing") }
return url
}
}
Кодовые ключи необходимо исключить songURL
из декодирования.
Если все аудиофайлы являются файлами mp3, вы даже можете опустить расширение в JSON, и вычисляемое свойство станет намного короче
struct Loop : Decodable {
let name, producer, count, genre, imagename, songName : String
private enum CodingKeys : String, CodingKey { case name, producer, count, genre, imagename, songName }
var songURL : URL {
guard let url = Bundle.main.url(forResource: songName, withExtension: "mp3") else { fatalError("Audio file is missing") }
return url
}
}
Теперь вы можете изменить playLoop
метод на
func playLoop(songURL: URL) {
audioPlayer = try! AVAudioPlayer(contentsOf: songURL)
audioPlayer.play()
print(songURL.lastPathComponent)
}
и воспроизведите песню с помощью метода нажатия
else { //IF PAUSE BUTTON
playLoop(songURL: loopsName[indexPath.row].songURL)
currentPlayingIndex = cell.tag
}
Этот метод gettingSongName()
не нужен. Кстати это можно написать в 2 строчки
func gettingSongName() {
guard let mp3URLs = Bundle.main.urls(forResourcesWithExtension: "mo3", subdirectory: nil) else { return }
songs = mp3URLs.map{$0.deletingPathExtension().lastPathComponent}
}
Примечания:
- Никогда не вызывайте
absoluteString
URL-адрес файловой системы, вы можете просто получить путь сpath
помощью . - Назовите свой массив источников данных
loops
и элемент вcellforRow
loop
нем . Ваше имя довольно сбивает с толку.
Комментарии:
1. Получение этого: Поток 1: Фатальная ошибка: Отсутствует аудиофайл
2. Когда я попробовал решение с mp3, у меня возникла ошибка. Но теперь я попробовал это: var songURL : URL { пусть компоненты = Имя песни.компоненты(разделено: «.») . количество компонентов == 2, пусть url = Bundle.main.url(для источника: компоненты[0], с расширением: компоненты[1]) иначе { Фатальная ошибка(«Отсутствует аудиофайл») } возвращает url }