I have two folders, each of them contains image, name of song and JSON file: Need to figure out, how to load data from each of JSON. Maybe it should be an array. JSON Files:
Second folder:
{
"beatpacktwo":
{
"twoloops": [
{
"name": "Midnight",
"producer": "Stefan Guy",
"count": "32",
"genre": "R&B",
"imagename": "beatpacktwo"
}
]
}
}
First folder:
{
"beatpackone":
{
"oneloops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop",
"imagename": "beatpackone"
}
]
}
}
Here is the swift file for each of folder: BeatPackTwo
import Foundation
import UIKit
struct BeatPackTwo: Decodable {
let beatpacktwo: BeatPackDataTwo
}
struct BeatPackDataTwo: Decodable {
let oneloops: [LoopTwo]
}
struct LoopTwo: Decodable {
let name: String
let producer: String
let count: String
let genre: String
let imagename: String
}
public class DataLoaderTwo {
func parseJSONtwo() -> BeatPackDataTwo? {
guard let url = Bundle.main.url(forResource: "beatpacktwo", withExtension: "json") else {
print("\n-------> bundle path error")
return nil
}
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(BeatPackTwo.self, from: jsonData)
print("\n-------> response: \(response)")
return response.beatpacktwo
}
catch {
print("\n====> error: \(error)" )
return nil
}
}
}
BeatPackOne:
import Foundation
import UIKit
struct BeatPackOne: Decodable {
let beatpackone: BeatPackDataOne
}
struct BeatPackDataOne: Decodable {
let oneloops: [LoopOne]
}
struct LoopOne: Decodable {
let name: String
let producer: String
let count: String
let genre: String
let imagename: String
}
public class DataLoaderOne {
func parseJSONone() -> BeatPackDataOne? {
guard let url = Bundle.main.url(forResource: "beatpackone", withExtension: "json") else {
print("\n-------> bundle path error")
return nil
}
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(BeatPackOne.self, from: jsonData)
print("\n-------> response: \(response)")
return response.beatpackone
}
catch {
print("\n====> error: \(error)" )
return nil
}
}
}
I've tried to create an instance in view controller, but now I can load the data from the one JSON file only, need to load from each of them and numberofrows in section should return count of the folders. Here is my tableview in view controller:
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(beatLoops.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
}
It should be something like that:
CodePudding user response:
There is no reason to have two JSON with different structures in your case:
Let's have instead:
{
"beatPack":
{
"loops": [
{
"name": "Midnight",
"producer": "Stefan Guy",
"count": "32",
"genre": "R&B",
"imagename": "beatpacktwo"
}
]
}
}
and
{
"beatPack":
{
"loops": [
{
"name": "Away we go",
"producer": "Tubular Kingz",
"count": "28",
"genre": "Lo-fi Hip Hop",
"imagename": "beatpackone"
}
]
}
}
I kept beatPack
& loops
, but that might even be irrelevant to keep them.
Then we have for our model:
struct TopLevel: Decodable {
let beatPack: BeatPack
}
struct BeatPack: Decodable {
let loops: [Loop]
}
struct Loop: Decodable {
let name: String
let producer: String
let count: String
let genre: String
let imagename: String
}
Then, to parse them:
In your BPLibraryViewController
:
var loopsName = [Loop]()
func parseJSON(file fileName: String) -> BeatPack? {
guard let url = Bundle.main.url(forResource: fileName, withExtension: "json") else {
print("\n-------> bundle path error: File \(fileName) not found")
return nil
}
do {
let jsonData = try Data(contentsOf: url)
let response = try JSONDecoder().decode(TopLevel.self, from: jsonData)
print("\n-------> response: \(response)")
return response.beatPack
}
catch {
print("\n====> error: \(error)" )
return nil
}
}
func retrieveLoops() -> [Loop] {
let packOne = parseJSON(file: "beatpackone")
let packTwo = parseJSON(file: "beatpacktwo")
var loops = [Loop]()
loops.append(contentsOf: packOne?.loops ?? [])
loops.append(contentsOf: packTwo?.loops ?? [])
// or, if you prefer more explicitly:
// if let loopOne = packOne?.loops {
// loops.append(contentsOf: loopOne)
// }
return loops
}
func prepareInit() {
loopsNames = retrieveLoops()
tableView.reloadData()
}