JSON 未加载到表视图中

Posted

技术标签:

【中文标题】JSON 未加载到表视图中【英文标题】:JSON isn't loading in the Table view 【发布时间】:2018-07-05 07:03:37 【问题描述】:

这是我的带有表格视图的视图控制器

class HomeVC: UIViewController, UITableViewDelegate, UITableViewDataSource     

    private let myArray: NSArray = ["First", "Second", "Third"]
    private var myTableView: UITableView!

    var articles: [ArticleClass]? = []


    override func viewDidLoad() 
        super.viewDidLoad()

        view.backgroundColor = UIColor.white
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.title = "Home"

        getData()

        let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
        let displayWidth: CGFloat = self.view.frame.width
        let displayHeight: CGFloat = self.view.frame.height

        myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
        myTableView.dataSource = self
        myTableView.delegate = self
        myTableView.register(ArticleCell.self, forCellReuseIdentifier: "MyCell")

        view.addSubview(myTableView)
        myTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        myTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        myTableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
        myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    


    func getData() 

        let theURL = URL(string: "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=34e81be767734526b224ac353b1378e8")
        let task = URLSession.shared.dataTask(with: theURL!)  (data, response, error) in

            if error != nil 

                print(error)
                return

             else 

                self.articles = [ArticleClass]()

                do 

                    let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]

                    if let articlesFromJSON = json["Articles"] as? [[String: Any]] 

                        for articleOutOfJSON in articlesFromJSON 

                            let theArticle = ArticleClass()

                            if let title = articleOutOfJSON as? String, let author = articleOutOfJSON["author"] as? String, let desc = articleOutOfJSON["description"] as? String, let url = articleOutOfJSON["url"] as? String, let imageToURL = articleOutOfJSON["imageToURL"] as? String 

                                theArticle.theDescription = desc
                                theArticle.author = author
                                theArticle.imageURL = imageToURL
                                theArticle.url = url

                            

                            //Putting the articleOutOfJSON into our array.
                            self.articles?.append(theArticle)

                        

                    

                    //Making the data be on the main thread.
                    DispatchQueue.main.async 

                        self.myTableView.reloadData()

                    


                 catch 

                    print(error)

                

            

        

        task.resume()

    




    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 1
    

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

        let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! ArticleCell

        cell.title.text = self.articles?[indexPath.item].headline
        cell.theDesc.text = self.articles?[indexPath.item].theDescription
        cell.author.text = self.articles?[indexPath.item].author
        cell.theImageView.downloadImage(from: (self.articles?[indexPath.item].url)!)

        return cell

    

    func numberOfSections(in tableView: UITableView) -> Int 
        return self.articles?.count ?? 0
    



这是我的表格视图单元格。

class ArticleCell: UITableViewCell 

    let title: UILabel = 
        let label = UILabel()
        label.text = "Title"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    let theDesc: UILabel = 
        let label = UILabel()
        label.text = "TEXT TEXT TEXT TEXT TEXT TEXT"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    let author: UILabel = 
        let label = UILabel()
        label.text = "Author"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    let theImageView: UIImageView = 
        let image = UIImageView()
        image.backgroundColor = UIColor.purple
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    ()

    override func awakeFromNib() 
        super.awakeFromNib()

        contentView.addSubview(theImageView)
        theImageView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 8).isActive = true
        theImageView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -146).isActive = true
        theImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 30).isActive = true
        theImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -26).isActive = true

        contentView.addSubview(title)
        contentView.addSubview(theDesc)
        contentView.addSubview(author)

    

    override func setSelected(_ selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    


这是我的数据模型。

class ArticleClass: NSObject 
    var headline: String?
    var theDescription: String?
    var author: String?
    var url: String?
    var imageURL: String?
    var publishingDate: Int?

我尝试将 JSON 加载到我的表格视图中,但它不起作用。我目前看不出我的代码有什么问题。如果您能提供帮助,我将不胜感激。我也在网上寻求帮助,但根据我遇到的问题无法获得任何帮助。

【问题讨论】:

欢迎来到 ***。请发布文字,而不是图片 您是否在Articles 对象中获取数据? 只需使用代码更新您的帖子。谢谢。 self.myTableView.reloadData() 设置断点并像@DharmeshKheni 所说的那样检查你的self.articles 检查关键访问文章,应该是文章 【参考方案1】:

我推荐使用Decodable 协议来解析JSON。

首先你不需要继承自NSObject 的类,结构体就足够了。文章结构使用 JSON 键作为属性:

struct News : Decodable 
    let status : String
    let articles : [Article]


struct Article : Decodable 
    let description: String?
    let author: String?
    let url: URL
    let urlToImage: URL?
    let publishedAt: Date

然后将数据源数组声明为非可选

var articles = [Article]()

然后解析JSON

func getData() 
    let theURL = URL(string: "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=••••••••••••••••••••")
    let task = URLSession.shared.dataTask(with: theURL!)  (data, response, error) in

        if error != nil  
           print(error!)
           return 
         else 
           do 
                let decoder = JSONDecoder()
                decoder.dateDecodingStrategy = .iso8601
                let news = try decoder.decode(News.self, from: data!)
                self.articles = news.articles

                //Making the data be on the main thread.
                DispatchQueue.main.async 
                    self.myTableView.reloadData()
                
             catch 
                print(error)
                     
        
    
    task.resume()


您的代码中还有其他问题

您混淆了numberOfSectionsnumberOfRowsInSection。在numberOfSections中返回1或者省略方法

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

numberOfRowsInSection返回文章数

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

cellForRow 中使用.row 而不是.item

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! ArticleCell
    let article = self.articles[indexPath.row]
    cell.title.text = article.title
    cell.theDesc.text = article.description
    cell.author.text = article.author
    cell.theImageView.downloadImage(from: article.url)
    return cell

PS:

强烈建议您不要在公共论坛上分享您的真实 API 密钥。更好的方法是发布 JSON 并乱码密钥

【讨论】:

【参考方案2】:

此行if let articlesFromJSON = json["Articles"] as? [[String: Any]] 应该是

if let articlesFromJSON = json["articles"] as? [[String: Any]] 

【讨论】:

【参考方案3】:

正如 Husyn 的回答中所建议的,您需要更换

if let articlesFromJSON = json["Articles"] as? [[String: Any]] 

if let articlesFromJSON = json["articles"] as? [[String: Any]] 

因为您的 Articles 密钥与来自服务器的数据不匹配,并且还有一个不匹配的密钥 imageToURL 需要根据您来自服务器的数据和您的数据替换为 urlToImage最终代码将是:

let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]

                if let articlesFromJSON = json["articles"] as? [[String: Any]] 
                    for articleOutOfJSON in articlesFromJSON 

                        let theArticle = ArticleClass()

                        if let title = articleOutOfJSON["title"] as? String, let author = articleOutOfJSON["author"] as? String, let desc = articleOutOfJSON["description"] as? String, let url = articleOutOfJSON["url"] as? String, let imageToURL = articleOutOfJSON["urlToImage"] as? String 

                            theArticle.theDescription = desc
                            theArticle.author = author
                            theArticle.imageURL = imageToURL
                            theArticle.url = url

                        
                        self.articles?.append(theArticle)
                    

                

如果服务器将发送null 值,那么整个对象将不会附加到您的articles 对象中。所以为了更好的方式检查下面的代码:

let theArticle = ArticleClass()
theArticle.theDescription = articleOutOfJSON["description"] as? String ?? ""
theArticle.author = articleOutOfJSON["author"] as? String ?? ""
theArticle.imageURL = articleOutOfJSON["urlToImage"] as? String ?? ""
theArticle.url = articleOutOfJSON["url"] as? String ?? ""
self.articles?.append(theArticle)

numberOfRowsInSection 应该是:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return self.articles?.count ?? 0

然后删除:

func numberOfSections(in tableView: UITableView) -> Int 
    return self.articles?.count ?? 0

【讨论】:

以上是关于JSON 未加载到表视图中的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Json 数据发送到表视图数组?迅速

将嵌套的 JSON 数据列出到表视图

处理 JSON 分页,并将数据添加到表视图?

将 customTableView 添加到未正确加载 json 数据的视图上

将文件 url 从 documentDirectory 加载到表视图

尝试仅将某些实体加载到表视图中