这是我的具有表视图的视图控制器
class HomeVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let myArray: NSArray = ["First", "Second", "Third"]
private var myTableView: UITableView!
var articles: [ArticleClass]? = []
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Home"
getData()
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.dataSource = self
myTableView.delegate = self
myTableView.register(ArticleCell.self, forCellReuseIdentifier: "MyCell")
view.addSubview(myTableView)
myTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
myTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
myTableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func getData() {
let theURL = URL(string: "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=34e81be767734526b224ac353b1378e8")
let task = URLSession.shared.dataTask(with: theURL!) { (data, response, error) in
if error != nil {
print(error)
return
} else {
self.articles = [ArticleClass]()
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let articlesFromJSON = json["Articles"] as? [[String: Any]] {
for articleOutOfJSON in articlesFromJSON {
let theArticle = ArticleClass()
if let title = articleOutOfJSON as? String, let author = articleOutOfJSON["author"] as? String, let desc = articleOutOfJSON["description"] as? String, let url = articleOutOfJSON["url"] as? String, let imageToURL = articleOutOfJSON["imageToURL"] as? String {
theArticle.theDescription = desc
theArticle.author = author
theArticle.imageURL = imageToURL
theArticle.url = url
}
//Putting the articleOutOfJSON into our array.
self.articles?.append(theArticle)
}
}
//Making the data be on the main thread.
DispatchQueue.main.async {
self.myTableView.reloadData()
}
} catch {
print(error)
}
}
}
task.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! ArticleCell
cell.title.text = self.articles?[indexPath.item].headline
cell.theDesc.text = self.articles?[indexPath.item].theDescription
cell.author.text = self.articles?[indexPath.item].author
cell.theImageView.downloadImage(from: (self.articles?[indexPath.item].url)!)
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.articles?.count ?? 0
}
}
这是我的表格视图单元格。
class ArticleCell: UITableViewCell {
let title: UILabel = {
let label = UILabel()
label.text = "Title"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let theDesc: UILabel = {
let label = UILabel()
label.text = "TEXT TEXT TEXT TEXT TEXT TEXT"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let author: UILabel = {
let label = UILabel()
label.text = "Author"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let theImageView: UIImageView = {
let image = UIImageView()
image.backgroundColor = UIColor.purple
image.translatesAutoresizingMaskIntoConstraints = false
return image
}()
override func awakeFromNib() {
super.awakeFromNib()
contentView.addSubview(theImageView)
theImageView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 8).isActive = true
theImageView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -146).isActive = true
theImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 30).isActive = true
theImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -26).isActive = true
contentView.addSubview(title)
contentView.addSubview(theDesc)
contentView.addSubview(author)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
这是我的数据模型。
class ArticleClass: NSObject {
var headline: String?
var theDescription: String?
var author: String?
var url: String?
var imageURL: String?
var publishingDate: Int?
}
我尝试将JSON加载到表视图中,但无法正常工作。我目前看不到代码有什么问题。如果可以的话,我将不胜感激。我也一直在网上寻求帮助,但由于遇到的问题而无法获得任何帮助。
答案 0 :(得分:3)
我建议使用Decodable
协议来解析JSON。
首先,您不需要从NSObject
继承的类,一个结构就足够了。本文结构使用JSON键作为属性:
struct News : Decodable {
let status : String
let articles : [Article]
}
struct Article : Decodable {
let description: String?
let author: String?
let url: URL
let urlToImage: URL?
let publishedAt: Date
}
然后将数据源数组声明为非可选
var articles = [Article]()
然后解析JSON
func getData() {
let theURL = URL(string: "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=••••••••••••••••••••")
let task = URLSession.shared.dataTask(with: theURL!) { (data, response, error) in
if error != nil {
print(error!)
return
} else {
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let news = try decoder.decode(News.self, from: data!)
self.articles = news.articles
//Making the data be on the main thread.
DispatchQueue.main.async {
self.myTableView.reloadData()
}
} catch {
print(error)
}
}
}
task.resume()
}
您的代码中还有其他问题:
您正在混合numberOfSections
和numberOfRowsInSection
。在numberOfSections
中返回1或忽略方法
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
在numberOfRowsInSection
中返回文章数
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return articles.count
}
在cellForRow
中使用.row
而不是.item
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! ArticleCell
let article = self.articles[indexPath.row]
cell.title.text = article.title
cell.theDesc.text = article.description
cell.author.text = article.author
cell.theImageView.downloadImage(from: article.url)
return cell
}
PS:
强烈建议您不要在公共论坛上共享真实的API密钥。更好的方法是发布JSON并使密钥乱码。
答案 1 :(得分:2)
此行if let articlesFromJSON = json["Articles"] as? [[String: Any]] {
应该是
if let articlesFromJSON = json["articles"] as? [[String: Any]] {
答案 2 :(得分:2)
根据Husyn的回答,您需要替换
if let articlesFromJSON = json["Articles"] as? [[String: Any]] {
与
if let articlesFromJSON = json["articles"] as? [[String: Any]] {
因为您的Articles
密钥与来自服务器的数据不匹配,还有另外一个与密钥不匹配的密钥是imageToURL
,根据您的需要,该密钥需要替换为urlToImage
来自服务器的数据以及您的最终代码将是:
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let articlesFromJSON = json["articles"] as? [[String: Any]] {
for articleOutOfJSON in articlesFromJSON {
let theArticle = ArticleClass()
if let title = articleOutOfJSON["title"] as? String, let author = articleOutOfJSON["author"] as? String, let desc = articleOutOfJSON["description"] as? String, let url = articleOutOfJSON["url"] as? String, let imageToURL = articleOutOfJSON["urlToImage"] as? String {
theArticle.theDescription = desc
theArticle.author = author
theArticle.imageURL = imageToURL
theArticle.url = url
}
self.articles?.append(theArticle)
}
}
如果服务器将发送null
值,则整个对象将不会追加到您的articles
对象中。因此,为了更好的方法,请检查以下代码:
let theArticle = ArticleClass()
theArticle.theDescription = articleOutOfJSON["description"] as? String ?? ""
theArticle.author = articleOutOfJSON["author"] as? String ?? ""
theArticle.imageURL = articleOutOfJSON["urlToImage"] as? String ?? ""
theArticle.url = articleOutOfJSON["url"] as? String ?? ""
self.articles?.append(theArticle)
numberOfRowsInSection
应该是:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.articles?.count ?? 0
}
然后删除:
func numberOfSections(in tableView: UITableView) -> Int {
return self.articles?.count ?? 0
}