ios - UICollectionView 在进行另一个 API 调用 Swift 时不加载新数据
问题描述
在这里,我尝试使用从 API 调用获取的另一个数据加载 collectionView。起初,我将数据加载调用到 CollectionView 中并且它可以工作,但是当滚动到底部时,我调用 scrollview 中的一个方法来获取更多数据,数据返回但集合视图没有更新。我有一个管理 API 调用的结构,它将通过委托传递给另一个 VC 并将其附加到数组中。
我期待什么
- 从 API 调用中获取的另一个数据将加载到 collectionView
究竟发生了什么
- 数据只能在第一次调用时加载,当尝试获取另一个调用时,collectionView 不会更新并保持刷新从早期 API 调用获得的第一个数据
这是我管理网络的课程
新闻管理器.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)")
}
}
}
解决方案
推荐阅读
- datadog - 如何在没有 Datadog 代理的情况下将日志发送到 Datadog
- python - python / Jupyter Notebook中的无限循环停止工作
- selenium - 机器人框架:如果任何关键字在循环内失败,则继续 FOR 循环
- javascript - jquery删除其他div中的div
- wordpress - 只有第一个产品图像出现在 woocommerce 中,其余的不起作用
- sql - 当字符串中有换行符时,Oracle 中的 SUBSTR 不起作用
- gradle - gradle如何获取第三方库的所有依赖?
- python - Python代码在csv文件中只打印一行
- flutter - 与 expect() 函数比较时,包含 List 的 Dartz Right 会抛出错误
- node.js - 政策中的格式错误的政策文档语法错误