如何使用 swift 从本地 JSON 加载数据到表视图中的标签 [英] How to load data from local JSON to the labels in table view using swift

查看:32
本文介绍了如何使用 swift 从本地 JSON 加载数据到表视图中的标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将数据从 JSON 加载到表格视图单元格中的标签时遇到一些问题.数据正在工作,我可以打印它,但是当我尝试加载时,它显示错误索引超出范围"或只有空表视图.这是我在视图控制器中加载 JSON 的模型和函数:

Have some problem with loading data from JSON to my labels in table view cell. Data is working, I can print it, but when I trying to load, it shows an error "Index out of range" or only empty table view. Here is my model and function to load JSON in view controller:

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()这是我的表格视图方法:

On the top of view controller, I've created an instance: let dataNew = DataLoader() Here is my table view 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.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 文件:

Also here is my JSON file:

{
    "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")
    }

推荐答案

你一直在编辑和更改数据,最新版本把一切都搞砸了.
这是一个经过测试的工作版本,请仔细阅读并复制/粘贴数据.

You are continuously editing and changing the data, the latest version messed everything up.
This is a tested working version, please read and copy/paste the data carefully.

这是 JSON(略有缩短)

This is the JSON (a bit shortened)

{
    "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
}

@Publisher 属性没有Combine 没有意义,用下面的替换类,解析器返回BeatPackData 对象或nil发生错误的情况

The @Publisher attribute makes no sense without Combine, replace the class with the following, the parser returns the BeatPackData object or nil in case of an error

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
        }
        
    }
}

这是视图控制器中的相关代码

This is the relevant code in the view controller

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
    }
}

这篇关于如何使用 swift 从本地 JSON 加载数据到表视图中的标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆