Manuel Duarte
Manuel Duarte

Reputation: 165

JSON to UITableView Swift 4 recently played songs

I'm still very new to coding so please go easy on me. My issue I'm having is I am trying to add my recently played songs to my Radio Station's app. I added a tableviewcontroller and added the cell already. The cell is setup with album artwork(cover), song title(title) and song artist(artist). I'm just stuck at getting the JSON info into my cell. Here is what my JSON data looks like. Any help is appreciated. Thanks

I switched this line:

guard let urlText = URL (string: "http://streamdb3web.securenetsystems.net/player_status_update/JACKSON1_history.txt")

To this line:

guard let urlText = URL (string: currentStation.longDesc)

Here is the error I get: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Upvotes: 1

Views: 529

Answers (1)

PongBongoSaurus
PongBongoSaurus

Reputation: 7385

As @nayem said it is best to read through some tutorials to learn about parsing JSON and how to deal with your response.

Here is an example in which I just copied your JSON Data and made a JSON file within the MainBundle:

//---------------------
//MARK: Your CustomCell
//---------------------

class YourCell: UITableViewCell{

@IBOutlet var songTitle: UILabel!
@IBOutlet var artistLabel: UILabel!
@IBOutlet var songCover: UIImageView!
}

//----------
//MARK: JSON
//----------

//The Initial Response From The JSON
struct Response: Codable {

var playHistory: Album


}

//The Album Received Which Is An Array Of Song Data
struct Album: Codable {
var song: [SongData]

}

//The SongData From The PlayHistory Album
struct SongData: Codable{

var album: String
var artist: String
var cover: String
var duration: String
var programStartTS: String
var title: String

}

//-----------------
//MARK: UITableView
//-----------------

extension ViewController: UITableViewDataSource{


func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return songs.count
}


   override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    //1. Create A Cell
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCell

    //2. Set It's Text
    cell.songTitle.text = songs[indexPath.row].title
    cell.artistLabel.text = songs[indexPath.row].artist

    //3. Get The Image
    if let imageURL = URL(string: songs[indexPath.row].cover){

        let request = URLSession.shared.dataTask(with: imageURL) { (imageData, response, error) in

            if let error = error{

                print(error)

            }else{

                guard let image = imageData else { return }

                DispatchQueue.main.async {
                    cell.songCover.image = UIImage(data: image)
                    cell.setNeedsLayout()
                    cell.layoutIfNeeded()
                }

            }
        }


        request.resume()
    }

    return cell

}

extension ViewController: UITableViewDelegate{

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    print("""
        **Album \(indexPath.row) Selected**
        Album = \(songs[indexPath.row].album)
        Artist = \(songs[indexPath.row].artist)
        Cover = \(songs[indexPath.row].cover)
        Duration = \(songs[indexPath.row].duration)
        Start = \(songs[indexPath.row].programStartTS)
        Title = \(songs[indexPath.row].title)
        """)
   }

  }

class ViewController: UIViewController {

//1. Create An Array To Store The SongData
var songs = [SongData]()

//2. Create A UITableView As An IBOutlet
@IBOutlet var albumTableView: UITableView!

override func viewDidLoad() { super.viewDidLoad()

    albumTableView.delegate = self
    albumTableView.dataSource = self

    //2. Load The JSON From The URL
    guard let urlText = URL(string:"https://streamdb3web.securenetsystems.net/player_status_update/JACKSON1_history.txt") else { return }

    do{
        //a. Get The Data From The From The File
        let data = try Data(contentsOf: urlText)

        //b. Decode The Data To Our Structs
        let albumData = try JSONDecoder().decode(Response.self, from: data)

        //c. Append The Songs Array With The PlayHistory
        albumData.playHistory.song.forEach { songs.append($0) }

        //d. Test Some Data
        print("""
            **The First Album Details**
            Album = \(songs[0].album)
            Artist = \(songs[0].artist)
            Cover = \(songs[0].cover)
            Duration = \(songs[0].duration)
            Start = \(songs[0].programStartTS)
            Title = \(songs[0].title)
        """)

        //3. Load The Data
        DispatchQueue.main.async {
            self.albumTableView.reloadData()
        }
    }catch{

        print(error)
    }

   }
}

Update: Using The Example Within A UITableViewController:

//---------------------
//MARK: Your CustomCell
//---------------------

class YourCell: UITableViewCell{

@IBOutlet var songTitle: UILabel!
@IBOutlet var artistLabel: UILabel!
@IBOutlet var songCover: UIImageView!

}

//----------
//MARK: JSON
//----------

//The Initial Response From The JSON
struct Response: Codable {

var playHistory: Album

}

//The Album Received Which Is An Array Of Song Data
struct Album: Codable {
var song: [SongData]

}

//The SongData From The PlayHistory Album
struct SongData: Codable{

var album: String
var artist: String
var cover: String
var duration: String
var programStartTS: String
var title: String
}


class ViewController: UITableViewController {

//1. Create An Array To Store The SongData
var songs = [SongData]()

override func viewDidLoad() { super.viewDidLoad()


    self.tableView.delegate = self
    self.tableView.dataSource = self

    //2. Load The JSON From The Main Bundle

    guard let urlText = URL(string:"https://streamdb3web.securenetsystems.net/player_status_update/JACKSON1_history.txt") else { return }


    do{
        //a. Get The Data From The From The File
        let data = try Data(contentsOf: urlText)

        //b. Decode The Data To Our Structs
        let albumData = try JSONDecoder().decode(Response.self, from: data)

        //c. Append The Songs Array With The PlayHistory
        albumData.playHistory.song.forEach { songs.append($0) }

        //d. Test Some Data
        print("""
            **The First Album Details**
            Album = \(songs[0].album)
            Artist = \(songs[0].artist)
            Cover = \(songs[0].cover)
            Duration = \(songs[0].duration)
            Start = \(songs[0].programStartTS)
            Title = \(songs[0].title)
            """)

        //3. Load The Data
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }catch{

        print(error)
    }

}

//-----------------
//MARK: UITableView
//-----------------


override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return songs.count
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    //1. Create A Cell
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCell

    //2. Set It's Text
    cell.songTitle.text = songs[indexPath.row].title
    cell.artistLabel.text = songs[indexPath.row].artist

    //3. Get The Image
    if let imageURL = URL(string: songs[indexPath.row].cover){

        let request = URLSession.shared.dataTask(with: imageURL) { (imageData, response, error) in

            if let error = error{

                print(error)

            }else{

                guard let image = imageData else { return }

                DispatchQueue.main.async {
                    cell.songCover.image = UIImage(data: image)
                    cell.setNeedsLayout()
                    cell.layoutIfNeeded()
                }

            }
        }


        request.resume()
    }

    return cell

}


override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    print("""
        **Album \(indexPath.row) Selected**
        Album = \(songs[indexPath.row].album)
        Artist = \(songs[indexPath.row].artist)
        Cover = \(songs[indexPath.row].cover)
        Duration = \(songs[indexPath.row].duration)
        Start = \(songs[indexPath.row].programStartTS)
        Title = \(songs[indexPath.row].title)
        """)
   }

  }

Upvotes: 0

Related Questions