在表视图中使用 JSON 编码错误

Posted

技术标签:

【中文标题】在表视图中使用 JSON 编码错误【英文标题】:JSON codable error while using in Table View 【发布时间】:2020-07-07 02:31:26 【问题描述】:

我正在使用 newsapi.org api 构建一个新闻应用程序。我能够从服务器获取数据并使用 JSON 解码器对其进行解码,但问题出在响应中,当我通过提供部分中的行数作为文章数组将文章数组作为数据源分配给表视图时,我得到了文章数组计数我收到一条错误消息,指出在 numberofrowsinsetction 方法中隐式展开可选值时意外发现 nil。

我能够在调试控制台中打印articles.count,目的是获取计数。但是当我将它分配给numberrowsinsection方法时,我得到了这个错误。

网络服务代码

import Foundation


class NetworkService
    
    
    static  let  sharedobj = NetworkService()
    let session = URLSession.shared
    
    
   private let HEADLINES_URL = "https://newsapi.org/v2/top-headlines?country=in&apiKey=API_key_HERE"
    
    public func getHeadLines(onSuccess: @escaping ([Articles]) -> Void)
    
        let datatask = session.dataTask(with: URL(string: HEADLINES_URL)!, completionHandler:  (data, response, error) in
            
            DispatchQueue.main.async 
                
                do
                
                    let decoder = try JSONDecoder().decode(Welcome.self, from: data!)
                    onSuccess(decoder.articles!)
                
                
                catch
                
                    print(error.localizedDescription)
                
                
               
            
            
            
            
            
            
        
        )
        
        datatask.resume()
        
        
        
    

查看控制器代码

import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
   
   
    var articles: [Articles]!
    var newsurl: String!
    
    @IBOutlet weak var headlinestableview: UITableView!
    override func viewDidLoad() 
        super.viewDidLoad()
       
        self.headlinestableview.delegate = self
        self.headlinestableview.dataSource = self
        
        NetworkService.sharedobj.getHeadLines  (a) in
            self.articles = a
            
            print(self.articles.count)
            
           
            
        
       
       
     
        
            
        
     
        
       
        
        
        
        
       
        
        
    

    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return articles.count
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        
        
       if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? HeadLinesCellTableViewCell
        
            
            let data = articles[indexPath.row]
            
            cell.updateCell(title:data.title ?? "Not Found", body: data.content ?? "No Body", imgurl: data.urlToImage ?? "https://en.wikipedia.org/wiki/Pages_(word_processor)#/media/File:Pages_Icon.png")
            
            newsurl = data.url
           
            return cell
            
        
        
        
        return UITableViewCell()
        
    
    
    
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        
        performSegue(withIdentifier: "segue", sender: self)
        
    
    
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        
        if let destinationVC = segue.destination as? BrowserVC
        
            destinationVC.url = newsurl
        
        
    


模型结构(使用 JSON 生成到 Swift 网站)

struct Welcome : Codable 
    let status : String?
    let totalResults : Int?
    let articles : [Articles]?

    enum CodingKeys: String, CodingKey 

        case status = "status"
        case totalResults = "totalResults"
        case articles = "articles"
    

    init(from decoder: Decoder) throws 
        let values = try decoder.container(keyedBy: CodingKeys.self)
        status = try values.decodeIfPresent(String.self, forKey: .status)
        totalResults = try values.decodeIfPresent(Int.self, forKey: .totalResults)
        articles = try values.decodeIfPresent([Articles].self, forKey: .articles)
    





struct Articles : Codable 
    let source : Source?
    let author : String?
    let title : String?
    let description : String?
    let url : String?
    let urlToImage : String?
    let publishedAt : String?
    let content : String?

    enum CodingKeys: String, CodingKey 

        case source = "source"
        case author = "author"
        case title = "title"
        case description = "description"
        case url = "url"
        case urlToImage = "urlToImage"
        case publishedAt = "publishedAt"
        case content = "content"
    

    init(from decoder: Decoder) throws 
        let values = try decoder.container(keyedBy: CodingKeys.self)
        source = try values.decodeIfPresent(Source.self, forKey: .source)
        author = try values.decodeIfPresent(String.self, forKey: .author)
        title = try values.decodeIfPresent(String.self, forKey: .title)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        url = try values.decodeIfPresent(String.self, forKey: .url)
        urlToImage = try values.decodeIfPresent(String.self, forKey: .urlToImage)
        publishedAt = try values.decodeIfPresent(String.self, forKey: .publishedAt)
        content = try values.decodeIfPresent(String.self, forKey: .content)
    




// MARK: - Source
struct Source : Codable 
    let id : String?
    let name : String?

    enum CodingKeys: String, CodingKey 

        case id = "id"
        case name = "name"
    

    init(from decoder: Decoder) throws 
        let values = try decoder.container(keyedBy: CodingKeys.self)
        id = try values.decodeIfPresent(String.self, forKey: .id)
        name = try values.decodeIfPresent(String.self, forKey: .name)
    


TableView 单元格代码

import UIKit

class HeadLinesCellTableViewCell: UITableViewCell 

    
    @IBOutlet weak var headlinesimageview: UIImageView!
    

    @IBOutlet weak var headlinestitlelbl: UILabel!
    
    @IBOutlet weak var headlinesbodylbl: UILabel!
    
    
    
    func updateCell(title: String,body: String,imgurl: String)
    
        headlinestitlelbl.text = title
        headlinesbodylbl.text = body
        
        DispatchQueue.global(qos: .userInitiated).async 
            
            if let data = try? Data(contentsOf: URL(string: imgurl)!)
        
                if let image = UIImage(data: data)
                
                    DispatchQueue.main.async 
                        self.headlinesimageview.image = image
                    
                

            
        
        
        
    
    
  
    
    




    
          
                
                
      

      
            
            
            
            
                
                
      
            
        
            
            
            
            
            
            
            
            

        
        
        
    
    
    

【问题讨论】:

我想没有人会喜欢看到这么多空行代码。 好的,等一下我改一下 var articles: [Articles]!改为var articles: [Articles] = [],在api响应文章之前调用datasource的方法。那时,它是空的。 现在它不会抛出错误但表格视图不显示数据 【参考方案1】:

而不是这个:

var articles: [Articles]!

用它来声明文章:

var articles = [Articles]()

更新:

在您的 didSelectRow 方法中执行以下操作:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
   
    let article = articles[indexPath.row]
    performSegue(withIdentifier: "segue", sender: article)
    

【讨论】:

@stark 您的初始化代码有问题。请检查此代码。 现在它不会抛出错误但表格视图不显示数据 另一个问题是,当我单击表格视图单元格时,它应该打开一个 Web 视图以显示新闻链接,但链接与表格视图单元格中的文章不匹配。 @Stark 如果它回答了您的原始问题,您可以投票并标记为正确答案 @stark 实现Didselectrow 方法,而不是DidDeselectrow 方法

以上是关于在表视图中使用 JSON 编码错误的主要内容,如果未能解决你的问题,请参考以下文章

IOS 内存错误,而 DELETE 按钮显示在表视图上

当我在表视图中配置它时,使用表视图 xib 常量空间正在消失

使用 Core Data 的 View Controller 中的表视图

在表视图或集合视图中删除与 IndexPath 关联的 CKRecord 的稳健方法是啥?

核心数据未在表视图中获取

如何在表视图中正确设置动态标题视图?