[英]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我期望发生的事情
What actually happens实际发生了什么
What I have tried to solve my problems我试图解决我的问题
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.