首页 > 解决方案 > UICollectionView 在进行另一个 API 调用 Swift 时不加载新数据

问题描述

在这里,我尝试使用从 API 调用获取的另一个数据加载 collectionView。起初,我将数据加载调用到 CollectionView 中并且它可以工作,但是当滚动到底部时,我调用 scrollview 中的一个方法来获取更多数据,数据返回但集合视图没有更新。我有一个管理 API 调用的结构,它将通过委托传递给另一个 VC 并将其附加到数组中。

我期待什么

究竟发生了什么

这是我管理网络的课程

新闻管理器.swift

import UIKit

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


struct NewsManager {
    
    var delegate : NewsManagerDelegate?

    let newsUrl = "https://gnews.io/api/v4/search?q="
    let key = "APIKEY"
    
    func fetchNews(topics : String = "Apple",page:Int = 1){
        let urlString = "\(newsUrl)\(topics)&lang=en&page=\(page)&token=\(key)"
        print(urlString)
        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()
        decoder.dateDecodingStrategy = .secondsSince1970
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        var newsModel = [NewsModel]()
        
        do{
    
            
            let decodeData = try decoder.decode(NewsData.self, from: newsData)
         
            
            print(decodeData.articles.count)
            
            for article in decodeData.articles {
                
            
                let newsTitle = article.title
                let newsDesc = article.description
                let newsURL = article.url
                let urlToImage = article.image
                let publishedAt = article.publishedAt
                let newsSource = article.source.name
                
                    let data = NewsModel(title: newsTitle, decription: newsDesc, url: newsURL, image: urlToImage, publishedAt: publishedAt, sourcesName: newsSource)
                    
                        newsModel.append(data)

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

        return newsModel
    }
}

**将填充数据的 ViewController

NewsCollectionVC.swift **

import UIKit
import SafariServices

class NewsCollectionVC: UIViewController {
    

    
    var newsManager = NewsManager()
    var newsResults = [NewsModel]()
    
    let iso8601Formatter = ISO8601DateFormatter()
    
    var dateFormatter : DateFormatter = {
        
        let formatter = DateFormatter()
        formatter.dateFormat = "dd-MM-yyyy"
        formatter.locale = Locale(identifier: "en_US_POSIX")
        return formatter
    }()
    
    var pageNumber = 1
    var fetchMoreNews = false
    
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureVC()
    }
    
    func configureVC(){
        
        collectionView.delegate = self
        collectionView.dataSource = self
        
        newsManager.delegate = self
        newsManager.fetchNews()
    }
    
}


extension NewsCollectionVC : UICollectionViewDataSource{
    
    
    // Tell delegate how many cv need to show
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        //return 2
        return newsResults.count
    }
    
    // Tell delegate content of cv
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let listOfNews = newsResults[indexPath.row]
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CViewCell
        
        cell.title.text = listOfNews.title
        cell.desc.text = listOfNews.decription
        cell.source.text = listOfNews.sourcesName
        
        // Convert damn ISO8601 to other format, https://developer.apple.com/forums/thread/660878
        if let date = iso8601Formatter.date(from: listOfNews.publishedAt){
            let formattedString = dateFormatter.string(from: date)
            cell.date.text = formattedString
        }
        
        cell.newsImage.downloaded(from: listOfNews.image)
        cell.newsImage.contentMode = .scaleAspectFill
        
        return cell
    }
    
}

extension NewsCollectionVC : UICollectionViewDelegate {
    
    
    // Function to fetch more news
    func fetchOtherNews(){
        
        fetchMoreNews = true
        print("Begin Fetch More News")
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
            
            print("Page number : \(self.pageNumber) | newResults : \(self.newsResults.count)")
            self.fetchMoreNews = false
            self.newsManager.fetchNews(page: self.pageNumber)
            
            self.collectionView.reloadData()
        }
    }
    
    
    // Tell delegate when user start scroll
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        let offSetY = scrollView.contentOffset.y
        let contentHeight = scrollView.contentSize.height
        
        if offSetY > contentHeight - scrollView.frame.height * 1 {
            
            if !fetchMoreNews{
                pageNumber += 1
                fetchOtherNews()
                collectionView.reloadData()
            }
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let selectedNews = newsResults[indexPath.row]
        // Provide VC to run url in app
        let SafariVC = SFSafariViewController(url: selectedNews.url)
        // Present the app
        present(SafariVC, animated: true, completion: nil)
        
    }
}


extension NewsCollectionVC : NewsManagerDelegate {
    
    func didSendNewsData(_ newsManager: NewsManager, with news: [NewsModel]) {
        
        DispatchQueue.main.async{
            
            self.newsResults.append(contentsOf: news)
            self.collectionView.reloadData()
            print("Current Page Number : \(self.pageNumber) | News Result :\(self.newsResults.count)")
            
        }
    }
}

标签: iosjsonswiftuicollectionview

解决方案


推荐阅读