如何使用 swift 将数据从本地 JSON 加载到 table 视图中的标签
How to load data from local JSON to the labels in table view using swift
将数据从 JSON 加载到我在 table 视图单元格中的标签时遇到一些问题。数据正在运行,我可以打印它,但是当我尝试加载时,它显示错误“索引超出范围”或只有空 table 视图。这是我在视图控制器中加载 JSON 的模型和函数:
import Foundation
import UIKit
struct BeatData: Decodable {
let data: [BeatPackData]
}
struct BeatPackData: Decodable {
let loops: [Loop]
let beatloops: [BeatLoop]
}
struct BeatLoop: Decodable {
let name: String
let instrument: String
let songName: String
let producer: String
}
struct Loop: Decodable {
let name: String
let producer: String
let count: String
let genre: String
}
public class DataLoader {
@Published var beatLoops = [BeatLoop]()
init() {
parseJSON()
}
// loadLoops()
// }
//
func parseJSON() {
guard let path = Bundle.main.path(forResource: "data", ofType: "json") else {
print("\n-------> bundle path error")
return
}
let url = URL(fileURLWithPath: path)
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(BeatData.self, from: jsonData)
self.brainLoops = response.data.beatloops
for beatPackData in response.data {
self.beatLoops.append(contentsOf: beatPackData.beatloops)
}
print("\n-------> response: \(response)")
}
catch {
print("\n====> error: \(error)" )
}
return
}
}
}
在视图控制器的顶部,我创建了一个实例:let dataNew = DataLoader()
这是我的 table 查看方法:
extension BeatPackViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataNew.beatLoops.count
// return dataNew.beatLoops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
// gettingSongName()
cell.loopNameLabel.text = dataNew.beatLoops[indexPath.row].name
cell.producerLabel.text = dataNew.beatLoops[indexPath.row].producer
cell.instrumentLabel.text = dataNew.beatLoops[indexPath.row].instrument
cell.delegate = self
cell.selectionStyle = .none
cell.tag = indexPath.row
// cell.playButtonOutlet.tag = indexPath.row
if let playingCell = currentPlayingIndex, playingCell == indexPath.row {
cell.playButtonOutlet.setImage(UIImage(named: "Pause.png"), for:
.normal)
} else {
cell.playButtonOutlet.setImage(UIImage(named: "playBtn.png"), for:
.normal)
}
return cell
}
这也是我的 JSON 文件:
{
"data": [
{
"beatloops": [
{
"name" : "Alien",
"instrument" :"Arp",
"songName" : "alienarpjason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Big Brake",
"instrument" :"Drums",
"songName" : "BigBrake_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Bongo Beats",
"instrument" :"Drums",
"songName" : "BongoBeats_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Dreaming",
"instrument" :"Keys",
"songName" : "Dreaming_Keys_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Funky Groove",
"instrument" :"Bass",
"songName" : "FunkyGroove_Bass_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Futurist",
"instrument" :"Arp",
"songName" : "Futurist_Arp_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Hoping for change",
"instrument" :"Arp",
"songName" : "HopingForChange_Arp_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Manic",
"instrument" :"Bass",
"songName" : "Manic_Bass_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Sassy",
"instrument" :"Drums",
"songName" : "Sassy_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Serious",
"instrument" :"Arp",
"songName" : "Serious_Arp_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Stable Bricks",
"instrument" :"Bass",
"songName" : "StableBrick_Bass_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Thump",
"instrument" :"Drums",
"songName" : "Thump_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Tropic",
"instrument" :"Drums",
"songName" : "TropicVibe_Drums_Jason.mp3",
"producer" : "Stefan Guy"
}
],
"loops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop"
},
{
"name": "Test",
"producer": "Testing",
"count": "25",
"genre": "Lo-fi"
}
],
}
]
}
我的视图控制器:
import UIKit
import AVFoundation
class BeatPackViewController: UIViewController, UIGestureRecognizerDelegate, UINavigationControllerDelegate {
@IBOutlet weak var beatView: UIView!
@IBOutlet weak var beatTableView: UITableView!
@IBOutlet weak var coverImage: UIImageView!
@IBOutlet weak var looppackNameLabel: UILabel!
@IBOutlet weak var producerNameLabel: UILabel!
@IBOutlet weak var backButtonLabel: UIButton!
var allButtons: [UIButton] = []
var currentPlayingIndex : Int?
// let data = [BeatData]()
let dataNew = DataLoader().beatLoops
var songs: [String] = []
var audioPlayer: AVAudioPlayer!
//MARK: - SONG METHODS
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()
}
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: "%20", with: " ")
mySong = mySong.replacingOccurrences(of: ".mp3", with: "")
songs.append(mySong)
}
}
} catch {
}
}
@IBOutlet var backButtonView: UIView!
@IBOutlet weak var baxkButtonView: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
beatTableView.delegate = self
beatTableView.dataSource = self
// parseJSON()
self.view.backgroundColor = SettingsService.sharedService.backgroundColor
coverImage.layer.cornerRadius = 20
coverImage.layer.shadowRadius = 7
coverImage.layer.shadowOpacity = 0.8
coverImage.layer.shadowOffset = CGSize(width: 3, height: 3)
coverImage.layer.shadowColor = UIColor.black.cgColor
coverImage.clipsToBounds = true
gettingSongName()
self.navigationController?.setNavigationBarHidden(true, animated: false)
let backButton = UIBarButtonItem(customView: self.baxkButtonView)
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
visualEffectView.frame = (self.navigationController?.navigationBar.bounds.insetBy(dx: 0, dy: -30).offsetBy(dx: 0, dy: -20))!
self.navigationController?.navigationBar.isTranslucent = true
// self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
// self.navigationController?.navigationBar.addSubview(visualEffectView)
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
// let backButtonItem = UIBarButtonItem(customView: self.backButton)
self.navigationController?.delegate = self
// self.navigationItem.leftBarButtonItem = backButtonItem
// self.navigationItem.leftBarButtonItem?.action = #selector(self.back(sender:))
self.navigationItem.leftBarButtonItem = backButton
}
@objc func back(sender: UIBarButtonItem) {
self.navigationController?.popViewController(animated: true)
print("done")
}
}
//MARK: TABLEVIEW DATASOURCE, DELEGATE METHODS
extension BeatPackViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataNew.count
// return dataNew.beatLoops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
// gettingSongName()
cell.loopNameLabel.text = dataNew[indexPath.row].name
// cell.loopNameLabel.text = dataNew.beatLoops[indexPath.row].name
// cell.producerLabel.text = dataNew.beatLoops[indexPath.row].producer
// cell.instrumentLabel.text = dataNew.beatLoops[indexPath.row].instrument
cell.delegate = self
cell.selectionStyle = .none
cell.tag = indexPath.row
// cell.playButtonOutlet.tag = indexPath.row
if let playingCell = currentPlayingIndex, playingCell == indexPath.row {
cell.playButtonOutlet.setImage(UIImage(named: "Pause.png"), for:
.normal)
} else {
cell.playButtonOutlet.setImage(UIImage(named: "playBtn.png"), for:
.normal)
}
return cell
}
//MARK: - Button Check
func btnUseTap(cell: CustomLoopsCell) {
let indexPath = self.beatTableView.indexPath(for: cell)
if currentPlayingIndex == cell.tag {
audioPlayer.pause()
currentPlayingIndex = nil
} else { //IF PAUSE BUTTON
playLoop(songName: songs[cell.tag])
currentPlayingIndex = cell.tag
}
beatTableView.reloadData()
// playSong(index: indexPath!.row)
print("Done")
}
在你的视图控制器的 viewDidLoad()
函数中,确保你 运行 你的 dataLoader 来获取数据。
在数据加载器中加载数据后,您需要向视图控制器发送一条消息,说明数据已准备好显示。
您可以通过以下方式做到这一点:
- 一个protocol/delegate
- 使用闭包作为完成处理程序
- 为您拥有的
@Published
属性设置观察者
- (如果您使用的是 iOS 15 测试版)使用 async/await
这部分有很多种方法,如果你选择一种,我可以更详细地解释。
获得数据后,运行 reloadData()
在 table 视图上。
你一直在编辑和更改数据,最新版本把一切都搞砸了。
这是一个经过测试的工作版本,请仔细阅读和copy/paste数据。
这是JSON(稍微缩短)
{
"data":
{
"beatloops": [
{
"name" : "Alien",
"instrument" :"Arp",
"songName" : "alienarpjason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Big Brake",
"instrument" :"Drums",
"songName" : "BigBrake_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Bongo Beats",
"instrument" :"Drums",
"songName" : "BongoBeats_Drums_Jason.mp3",
"producer" : "Stefan Guy"
}
],
"loops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop"
},
{
"name": "Test",
"producer": "Testing",
"count": "25",
"genre": "Lo-fi"
}
]
}
}
对应的结构是
struct BeatData: Decodable {
let data: BeatPackData
}
struct BeatPackData: Decodable {
let loops: [Loop]
let beatloops: [BeatLoop]
}
struct BeatLoop: Decodable {
let name: String
let instrument: String
let songName: String
let producer: String
}
struct Loop: Decodable {
let name: String
let producer: String
let count: String
let genre: String
}
如果没有 Combine,@Publisher
属性就没有意义,将 class 替换为以下内容,解析器 returns 中的 BeatPackData
对象或 nil
出现错误
public class DataLoader {
func parseJSON() -> BeatPackData? {
guard let url = Bundle.main.url(forResource: "data", withExtension: "json") else {
print("\n-------> bundle path error")
return nil
}
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(BeatData.self, from: jsonData)
print("\n-------> response: \(response)")
return response.data
}
catch {
print("\n====> error: \(error)" )
return nil
}
}
}
这是视图控制器中的相关代码
class BeatPackViewController: UIViewController {
@IBOutlet weak var beatTableView: UITableView!
var loops = [Loop]()
var beatLoops = [BeatLoop]()
override func viewDidLoad() {
super.viewDidLoad()
let loader = DataLoader()
guard let data = loader.parseJSON() else { return }
loops = data.loops
beatLoops = data.beatloops
beatTableView.reloadData()
}
}
extension BeatPackViewController : UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return beatLoops.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
let beatLoop = beatLoops[indexPath.row]
cell.loopNameLabel.text = beatLoop.name
cell.producerLabel.text = beatLoop.producer
cell.instrumentLabel.text = beatLoop.instrument
return cell
}
}
将数据从 JSON 加载到我在 table 视图单元格中的标签时遇到一些问题。数据正在运行,我可以打印它,但是当我尝试加载时,它显示错误“索引超出范围”或只有空 table 视图。这是我在视图控制器中加载 JSON 的模型和函数:
import Foundation
import UIKit
struct BeatData: Decodable {
let data: [BeatPackData]
}
struct BeatPackData: Decodable {
let loops: [Loop]
let beatloops: [BeatLoop]
}
struct BeatLoop: Decodable {
let name: String
let instrument: String
let songName: String
let producer: String
}
struct Loop: Decodable {
let name: String
let producer: String
let count: String
let genre: String
}
public class DataLoader {
@Published var beatLoops = [BeatLoop]()
init() {
parseJSON()
}
// loadLoops()
// }
//
func parseJSON() {
guard let path = Bundle.main.path(forResource: "data", ofType: "json") else {
print("\n-------> bundle path error")
return
}
let url = URL(fileURLWithPath: path)
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(BeatData.self, from: jsonData)
self.brainLoops = response.data.beatloops
for beatPackData in response.data {
self.beatLoops.append(contentsOf: beatPackData.beatloops)
}
print("\n-------> response: \(response)")
}
catch {
print("\n====> error: \(error)" )
}
return
}
}
}
在视图控制器的顶部,我创建了一个实例:let dataNew = DataLoader()
这是我的 table 查看方法:
extension BeatPackViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataNew.beatLoops.count
// return dataNew.beatLoops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
// gettingSongName()
cell.loopNameLabel.text = dataNew.beatLoops[indexPath.row].name
cell.producerLabel.text = dataNew.beatLoops[indexPath.row].producer
cell.instrumentLabel.text = dataNew.beatLoops[indexPath.row].instrument
cell.delegate = self
cell.selectionStyle = .none
cell.tag = indexPath.row
// cell.playButtonOutlet.tag = indexPath.row
if let playingCell = currentPlayingIndex, playingCell == indexPath.row {
cell.playButtonOutlet.setImage(UIImage(named: "Pause.png"), for:
.normal)
} else {
cell.playButtonOutlet.setImage(UIImage(named: "playBtn.png"), for:
.normal)
}
return cell
}
这也是我的 JSON 文件:
{
"data": [
{
"beatloops": [
{
"name" : "Alien",
"instrument" :"Arp",
"songName" : "alienarpjason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Big Brake",
"instrument" :"Drums",
"songName" : "BigBrake_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Bongo Beats",
"instrument" :"Drums",
"songName" : "BongoBeats_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Dreaming",
"instrument" :"Keys",
"songName" : "Dreaming_Keys_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Funky Groove",
"instrument" :"Bass",
"songName" : "FunkyGroove_Bass_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Futurist",
"instrument" :"Arp",
"songName" : "Futurist_Arp_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Hoping for change",
"instrument" :"Arp",
"songName" : "HopingForChange_Arp_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Manic",
"instrument" :"Bass",
"songName" : "Manic_Bass_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Sassy",
"instrument" :"Drums",
"songName" : "Sassy_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Serious",
"instrument" :"Arp",
"songName" : "Serious_Arp_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Stable Bricks",
"instrument" :"Bass",
"songName" : "StableBrick_Bass_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Thump",
"instrument" :"Drums",
"songName" : "Thump_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Tropic",
"instrument" :"Drums",
"songName" : "TropicVibe_Drums_Jason.mp3",
"producer" : "Stefan Guy"
}
],
"loops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop"
},
{
"name": "Test",
"producer": "Testing",
"count": "25",
"genre": "Lo-fi"
}
],
}
]
}
我的视图控制器:
import UIKit
import AVFoundation
class BeatPackViewController: UIViewController, UIGestureRecognizerDelegate, UINavigationControllerDelegate {
@IBOutlet weak var beatView: UIView!
@IBOutlet weak var beatTableView: UITableView!
@IBOutlet weak var coverImage: UIImageView!
@IBOutlet weak var looppackNameLabel: UILabel!
@IBOutlet weak var producerNameLabel: UILabel!
@IBOutlet weak var backButtonLabel: UIButton!
var allButtons: [UIButton] = []
var currentPlayingIndex : Int?
// let data = [BeatData]()
let dataNew = DataLoader().beatLoops
var songs: [String] = []
var audioPlayer: AVAudioPlayer!
//MARK: - SONG METHODS
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()
}
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: "%20", with: " ")
mySong = mySong.replacingOccurrences(of: ".mp3", with: "")
songs.append(mySong)
}
}
} catch {
}
}
@IBOutlet var backButtonView: UIView!
@IBOutlet weak var baxkButtonView: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
beatTableView.delegate = self
beatTableView.dataSource = self
// parseJSON()
self.view.backgroundColor = SettingsService.sharedService.backgroundColor
coverImage.layer.cornerRadius = 20
coverImage.layer.shadowRadius = 7
coverImage.layer.shadowOpacity = 0.8
coverImage.layer.shadowOffset = CGSize(width: 3, height: 3)
coverImage.layer.shadowColor = UIColor.black.cgColor
coverImage.clipsToBounds = true
gettingSongName()
self.navigationController?.setNavigationBarHidden(true, animated: false)
let backButton = UIBarButtonItem(customView: self.baxkButtonView)
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
visualEffectView.frame = (self.navigationController?.navigationBar.bounds.insetBy(dx: 0, dy: -30).offsetBy(dx: 0, dy: -20))!
self.navigationController?.navigationBar.isTranslucent = true
// self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
// self.navigationController?.navigationBar.addSubview(visualEffectView)
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
// let backButtonItem = UIBarButtonItem(customView: self.backButton)
self.navigationController?.delegate = self
// self.navigationItem.leftBarButtonItem = backButtonItem
// self.navigationItem.leftBarButtonItem?.action = #selector(self.back(sender:))
self.navigationItem.leftBarButtonItem = backButton
}
@objc func back(sender: UIBarButtonItem) {
self.navigationController?.popViewController(animated: true)
print("done")
}
}
//MARK: TABLEVIEW DATASOURCE, DELEGATE METHODS
extension BeatPackViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataNew.count
// return dataNew.beatLoops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
// gettingSongName()
cell.loopNameLabel.text = dataNew[indexPath.row].name
// cell.loopNameLabel.text = dataNew.beatLoops[indexPath.row].name
// cell.producerLabel.text = dataNew.beatLoops[indexPath.row].producer
// cell.instrumentLabel.text = dataNew.beatLoops[indexPath.row].instrument
cell.delegate = self
cell.selectionStyle = .none
cell.tag = indexPath.row
// cell.playButtonOutlet.tag = indexPath.row
if let playingCell = currentPlayingIndex, playingCell == indexPath.row {
cell.playButtonOutlet.setImage(UIImage(named: "Pause.png"), for:
.normal)
} else {
cell.playButtonOutlet.setImage(UIImage(named: "playBtn.png"), for:
.normal)
}
return cell
}
//MARK: - Button Check
func btnUseTap(cell: CustomLoopsCell) {
let indexPath = self.beatTableView.indexPath(for: cell)
if currentPlayingIndex == cell.tag {
audioPlayer.pause()
currentPlayingIndex = nil
} else { //IF PAUSE BUTTON
playLoop(songName: songs[cell.tag])
currentPlayingIndex = cell.tag
}
beatTableView.reloadData()
// playSong(index: indexPath!.row)
print("Done")
}
在你的视图控制器的 viewDidLoad()
函数中,确保你 运行 你的 dataLoader 来获取数据。
在数据加载器中加载数据后,您需要向视图控制器发送一条消息,说明数据已准备好显示。
您可以通过以下方式做到这一点:
- 一个protocol/delegate
- 使用闭包作为完成处理程序
- 为您拥有的
@Published
属性设置观察者 - (如果您使用的是 iOS 15 测试版)使用 async/await 这部分有很多种方法,如果你选择一种,我可以更详细地解释。
获得数据后,运行 reloadData()
在 table 视图上。
你一直在编辑和更改数据,最新版本把一切都搞砸了。
这是一个经过测试的工作版本,请仔细阅读和copy/paste数据。
这是JSON(稍微缩短)
{
"data":
{
"beatloops": [
{
"name" : "Alien",
"instrument" :"Arp",
"songName" : "alienarpjason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Big Brake",
"instrument" :"Drums",
"songName" : "BigBrake_Drums_Jason.mp3",
"producer" : "Stefan Guy"
},
{
"name" : "Bongo Beats",
"instrument" :"Drums",
"songName" : "BongoBeats_Drums_Jason.mp3",
"producer" : "Stefan Guy"
}
],
"loops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop"
},
{
"name": "Test",
"producer": "Testing",
"count": "25",
"genre": "Lo-fi"
}
]
}
}
对应的结构是
struct BeatData: Decodable {
let data: BeatPackData
}
struct BeatPackData: Decodable {
let loops: [Loop]
let beatloops: [BeatLoop]
}
struct BeatLoop: Decodable {
let name: String
let instrument: String
let songName: String
let producer: String
}
struct Loop: Decodable {
let name: String
let producer: String
let count: String
let genre: String
}
如果没有 Combine,@Publisher
属性就没有意义,将 class 替换为以下内容,解析器 returns 中的 BeatPackData
对象或 nil
出现错误
public class DataLoader {
func parseJSON() -> BeatPackData? {
guard let url = Bundle.main.url(forResource: "data", withExtension: "json") else {
print("\n-------> bundle path error")
return nil
}
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(BeatData.self, from: jsonData)
print("\n-------> response: \(response)")
return response.data
}
catch {
print("\n====> error: \(error)" )
return nil
}
}
}
这是视图控制器中的相关代码
class BeatPackViewController: UIViewController {
@IBOutlet weak var beatTableView: UITableView!
var loops = [Loop]()
var beatLoops = [BeatLoop]()
override func viewDidLoad() {
super.viewDidLoad()
let loader = DataLoader()
guard let data = loader.parseJSON() else { return }
loops = data.loops
beatLoops = data.beatloops
beatTableView.reloadData()
}
}
extension BeatPackViewController : UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return beatLoops.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
let beatLoop = beatLoops[indexPath.row]
cell.loopNameLabel.text = beatLoop.name
cell.producerLabel.text = beatLoop.producer
cell.instrumentLabel.text = beatLoop.instrument
return cell
}
}