【问题标题】:JSON to UITableView Swift 4 recently played songsJSON to UITableView Swift 4 最近播放的歌曲
【发布时间】:2018-03-05 02:49:15
【问题描述】:

我对编码还是很陌生,所以请放轻松。我遇到的问题是我正在尝试将我最近播放的歌曲添加到我的广播电台的应用程序中。我添加了一个 tableviewcontroller 并已经添加了单元格。单元格设置有专辑封面(封面)、歌曲标题(标题)和歌曲艺术家(艺术家)。我只是坚持将 JSON 信息输入我的单元格。这是我的 JSON 数据的样子。任何帮助表示赞赏。谢谢

我换了这条线:

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

到这一行:

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

这是我得到的错误:线程 1:致命错误:在展开可选值时意外发现 nil

【问题讨论】:

  • 你是如何反序列化 JSON 的?你把它解析成对象了吗?
  • @nayem 我不知道。我对编码非常陌生。我知道基础知识。大声笑
  • 好吧,好吧。然后你需要对你需要什么有一些基本的了解。一些谷歌搜索(如:Swift 4 中的 JSON 解码、UITableView 数据映射)将在这方面为您提供帮助。或者你可以看看this快速教程。

标签: ios json swift uitableview


【解决方案1】:

正如@nayem 所说,最好通读一些教程以了解解析 JSON 以及如何处理您的响应。

这是一个示例,其中我刚刚复制了您的 JSON 数据并在 MainBundle 中创建了一个 JSON 文件:

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

   }
}

更新: 在 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)
        """)
   }

  }

【讨论】:

  • 为什么结构中的成员声明为隐式展开可选?不要那样做。如果成员在 init 方法中初始化(Codable 所做的),则永远不要这样做。 JSON 清楚地提供了所有字段,因此将成员声明为非可选并删除感叹号。如果结构中采用Codable 的成员可以是nil,则将其声明为常规可选(?
  • 感谢您的反馈...希望我已经更新了我现在正确回答的尝试
  • @JoshRobbins 非常感谢先生。我一直在做大量的研究,但没有什么能清楚地解释我的情况。我的 JSON 不是本地的,它是:streamdb3web.securenetsystems.net/player_status_update/… 这会有所作为吗?
  • 您只需要更改网址...我已经更新了上面的答案。如果您对它感到满意,请标记为答案...
  • @JoshRobbins 我现在不断收到一堆错误;使用未声明的类型“UIViewController”也使用未声明的类型“UITableView”和“超级”成员也不能在根类中引用使用未解析的标识符“数据”。还有一些。
猜你喜欢
  • 1970-01-01
  • 2017-11-21
  • 1970-01-01
  • 1970-01-01
  • 2017-01-11
  • 2015-08-09
  • 2013-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多