简体   繁体   English

JSON 数据不会在 UICollectionView Swift 5 中加载

[英]JSON data do not load in UICollectionView Swift 5

currently I'm trying to load data from News API, before this I had tried to implement it with UITableView and it works but it not works in UICollectionView.目前我正在尝试从 News API 加载数据,在此之前我曾尝试使用 UITableView 实现它并且它有效但它在 UICollectionView 中无效。 I'm using URLSession for networking operations.我正在使用 URLSession 进行网络操作。

PS; PS; I did this with premade collectionView from object library in Storyborad我用 Storyborad 对象库中的预制 collectionView 做到了这一点

What I Expect to happen我期望发生的事情

  • JSON data load into CollectionView JSON 数据加载到 CollectionView

What actually happens实际发生了什么

  • JSON does not load in CollectionView and the screen is empty JSON 未在 CollectionView 中加载并且屏幕为空

What I have tried to solve my problems我试图解决我的问题

  • Reload collectionView after the JSON appends JSON 追加后重新加载 collectionView

NewsCollectionVC.swift NewsCollectionVC.swift

class NewsCollectionVC: UIViewController {

    var newsResult = [NewsModel]()
    var newsManager = NewsManager()
    @IBOutlet weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self
        newsManager.fetchNews()
        newsManager.delegate = self
        collectionView.reloadData()
    }
    
}

extension NewsCollectionVC : NewsManagerDelegate {
    func didSendNewsData(_ newsManager: NewsManager, with news: [NewsModel]) {
        
        self.newsResult.append(contentsOf: news)
        DispatchQueue.main.async{

            self.collectionView.reloadData()
            print(self.newsResult.count)
        }
    }
}

extension NewsCollectionVC : UICollectionViewDataSource{
    

    // Tell delegate how many cv need to show
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        

        return newsResult.count
    }
    
    // Tell delegate content of cv
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let listOfNews = newsResult[indexPath.row]
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CViewCell
        cell.author.text = listOfNews.author
        //cell.author.text = "listOfNews.author"
        
        return cell
    }
}

NewsManager.swift新闻管理器.swift

protocol NewsManagerDelegate {
    func didSendNewsData (_ newsManager: NewsManager, with news : [NewsModel])
}


struct NewsManager{
    
    var delegate : NewsManagerDelegate?
    
    let newsUrl = "https://newsapi.org/v2/everything?q=apple"
    let key = "MY_API_KEY"
    
    func fetchNews(){
        let urlString = "\(newsUrl)&apiKey=\(key)"
        performRequest(with : urlString)
    }
    
    func fetchNews(page : Int){
        let urlString = "\(newsUrl)&page=\(page)&apiKey=\(key)"
        performRequest(with: urlString)
    }

    
    func performRequest(with urlString : String){
        
        
        // 1. create URL object
        guard let url = URL(string: urlString) else {fatalError("There's problem to fetch data from this url")}
        
        // 2. create session, object to do networking
        let session = URLSession(configuration: .default)
        
        //3. give session a task
        let task = session.dataTask(with: url) { (data, response, error) in
            
            if error != nil{
                print("Error in giving session a task \(String(describing: error?.localizedDescription))")
                
            } else{
                // determine if data is exist
                if let safeData = data {
                    //convert data to string
                    //let dataString = String(data: safeData, encoding: .utf8)
                    //print(dataString)
                    
                    // Parse the data here
                    guard let news = parseJSON(safeData) else{ fatalError("Error parsing data from JSON")}
                   
                    DispatchQueue.main.async {
                        delegate?.didSendNewsData(self, with: news)
                    }
                    
                }
            }
        }
        //start the task
        task.resume()
    }
    
    func parseJSON(_ newsData : Data) -> [NewsModel]?{
        
        
        let decoder = JSONDecoder()
    
        var newsModel = [NewsModel]()
        
        do{
            
            let decodeData = try decoder.decode(NewsData.self, from: newsData)
            print(decodeData.articles[0].title)
            print(decodeData.articles[0].source.name)
            print(decodeData.articles[0].urlToImage)
            
            
          
            
            for article in decodeData.articles {
                
                let author = article.author
                let title = article.title
                let decription = article.description
                let url = article.url
                let urlToImage = article.urlToImage
                let publishedAt = article.publishedAt
                let sourcesName = article.source.name
                
                
                    guard let imageData = try? Data(contentsOf: urlToImage) else{fatalError("Error to get image data from URL")}
                     guard let imageContent = UIImage(data: imageData) else {fatalError("Error load image from image data")}
                    let data = NewsModel(author: author, title: title, decription: decription, url: url, image: imageContent, publishedAt: publishedAt, sourcesName: sourcesName)
                    
                        newsModel.append(data)

            }
            
            return newsModel
            
        } catch{
            print("Error decode the data : \(error.localizedDescription)")
    
        }

        return newsModel
    }
}

NewsModel.swift新闻模型.swift

struct NewsModel {
    let author : String
    let title : String
    let decription : String
    let url : String
    let image : UIImage
    let publishedAt : String
    let sourcesName : String
    
}

thank you for your time in answering these questions, the answer is because I assign the instance for the delegate after calling the instance methods.感谢您抽出时间回答这些问题,答案是因为我在调用实例方法后为委托分配了实例。

It should be ✅应该是✅

override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self

        newsManager.delegate = self
        newsManager.fetchNews()
        
        collectionView.reloadData()
    }

rather than ❎而不是 ❎

override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self
        newsManager.fetchNews()
        newsManager.delegate = self
        collectionView.reloadData()
    }

Add this to viewDidLoad:将此添加到 viewDidLoad:

collectionView.register(UINib(nibName: "CViewCell", bundle: nil), forCellWithReuseIdentifier: "cell")

You need to register the cell for the colletionView.您需要为 colletionView 注册单元格。 And it will be better if you put the code about colletionView together.而且如果你把关于colletionView的代码放在一起会更好。 You can create a function like func setupCollectionView() or just lazy load the colletionView.您可以创建一个函数,如func setupCollectionView()或只是延迟加载func setupCollectionView() That will be better.那会更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM