未使用 reloadData() 方法调用 cellForRowAt indexPath
Posted
技术标签:
【中文标题】未使用 reloadData() 方法调用 cellForRowAt indexPath【英文标题】:cellForRowAt indexPath is not being called with reloadData() method 【发布时间】:2017-01-03 15:31:49 【问题描述】:在 Swift 3 中,我正在尝试创建一个“过滤器”视图,让用户可以按类别和日期过滤表格视图中的帖子。目前,过滤器视图以模态方式呈现,并在您单击“完成”时关闭。
我还没有设置 日期/类别 功能。首先,我只是想让 tableView 更新以仅显示 3
的帖子,而不是 10
。为此,我在FilterViewController
中设置了destination.numPosts = 3
。
使用打印语句,可以看出TableViewController
实际上确实更新了viewDidLoad
函数中的帖子数组以拥有3
帖子。 numberOfRowsInSection
被调用并且是正确的。 numberofSections
总是返回 1
。在viewDidLoad
中,我尝试了self.tableView.reloadData()
和tableView.reloadData()
,但是,cellForRowAt indexPath
仅在您最初运行应用程序时被调用,而在数据重新加载时它不会调用它重新加载。
关于在FilterViewController
被解雇时如何重新填充帖子表的任何想法?
表格视图控制器:
import UIKit
class TableViewController: UITableViewController
let myArray = ["item 1", "item 2", "item 3"]
var posts = [Post]()
var numPosts = 9
override func viewDidLoad()
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
/*
let logo = UIImage(named: "860logo.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
*/
var titleView: UIImageView
titleView = UIImageView(frame:CGRect(x: 0, y: 0, width: 50, height: 60))
titleView.contentMode = .scaleAspectFit
titleView.image = UIImage(named: "860logo.png")
self.navigationItem.titleView = titleView
//titleView.backgroundColor = UIColor(red:0.18, green:0.20, blue:0.38, alpha:1.0)
let newPost = Post(id: 6503, title: "Work Zone Accident", date: "2016-12-05T09:24:47", url: "http://www.mlive.com/news/ann-arbor/index.ssf/2016/12/ann_arbor_brings_charges_again.html", category: "Work Zone Accidents")
let newPost2 = Post(id: 6501, title: "Anti-Union Laws (Unemployment)", date: "2016-12-05T09:24:19", url: "http://www.cleveland.com/opinion/index.ssf/2016/12/gop_lawmakers_from_high-jobles.html#incart_river_mobile_home", category: "Anti-Union Laws")
let newPost3 = Post(id: 6499, title: "Anti-Union Appointments", date: "2016-12-05T09:23:36", url: "http://prospect.org/article/trump-labor-secretary-could-be-fight-15-worst-nightmare", category: "Anti-Union Laws")
let newPost4 = Post(id: 6497, title: "Infrastructure", date: "2016-12-05T09:23:06", url: "http://www.cbpp.org/research/federal-budget/trump-infrastructure-plan-far-less-than-the-claimed-1-trillion-in-new", category: "infrastructure")
let newPost5 = Post(id: 6495, title: "Work Zone Accident", date: "2016-12-05T09:22:38", url: "http://www.marinij.com/general-news/20161202/construction-worker-struck-by-car-in-novato", category: "Work Zone Accidents")
let newPost6 = Post(id: 6493, title: "Infrastructure", date: "2016-12-05T09:22:03", url: "http://markets.businessinsider.com/news/stocks/There-could-be-an-unexpected-side-effect-of-Trumps-infrastructure-spending-1001554657", category: "infrastructure")
let newPost7 = Post(id: 6491, title: "Infrastructure", date: "2016-12-05T09:14:28", url: "http://www.nydailynews.com/opinion/build-not-burn-bridges-infrastructure-article-1.2890434", category: "infrastructure")
let newPost8 = Post(id: 6489, title: "Highway Funding", date: "2016-12-01T11:02:55", url: "http://www.gobytrucknews.com/democrats-want-highway-funds/123", category: "Funding")
let newPost9 = Post(id: 6487, title: "Highway Funding (Congressional Bottleneck)", date: "2016-12-01T11:02:00", url: "https://www.trucks.com/2016/12/01/raise-fuel-taxes-road-funding-traffic-relief/", category: "Funding")
let newPost10 = Post(id: 6485, title: "Highway Funding", date: "2016-12-01T11:01:24", url: "http://www.wsj.com/articles/numbers-dont-add-up-for-trumps-trillion-dollar-building-plan-1480538796", category: "Funding")
posts.removeAll()
print("Num Posts: \(self.numPosts)")
if numPosts >= 0 posts.append(newPost)
if numPosts >= 1 posts.append(newPost2)
if numPosts >= 2 posts.append(newPost3)
if numPosts >= 3 posts.append(newPost4)
if numPosts >= 4 posts.append(newPost5)
if numPosts >= 5 posts.append(newPost6)
if numPosts >= 6 posts.append(newPost7)
if numPosts >= 7 posts.append(newPost8)
if numPosts >= 8 posts.append(newPost9)
if numPosts >= 9 posts.append(newPost10)
print("Posts Count: \(posts.count)")
self.tableView.reloadData()
tableView.reloadData()
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
// MARK: - Table view data source
//Count Number of Sections
override func numberOfSections(in tableView: UITableView) -> Int
// #warning Incomplete implementation, return the number of sections
return 1
//Count Number of Rows in Section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// #warning Incomplete implementation, return the number of rows
print(posts.count)
return posts.count
//Populate Rows with Content
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
//DELETE let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let cell:CustomTableCell = self.tableView.dequeueReusableCell(withIdentifier: "Cell") as! CustomTableCell
cell.titleLabel?.text = posts[indexPath.item].title
//Format Date String, Set Cell's Date Text
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let stringDate = dateFormatter.string(from:posts[indexPath.item].date)
let dateYear = "\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:0)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:1)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:2)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:3)])"
let dateMonthNumber = Int("\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:5)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:6)])")
var dateMonth = ""
if dateMonthNumber == 01 dateMonth = "January"
else if dateMonthNumber == 02 dateMonth = "February"
else if dateMonthNumber == 03 dateMonth = "March"
else if dateMonthNumber == 04 dateMonth = "April"
else if dateMonthNumber == 05 dateMonth = "May"
else if dateMonthNumber == 06 dateMonth = "June"
else if dateMonthNumber == 07 dateMonth = "July"
else if dateMonthNumber == 08 dateMonth = "August"
else if dateMonthNumber == 09 dateMonth = "September"
else if dateMonthNumber == 10 dateMonth = "October"
else if dateMonthNumber == 11 dateMonth = "November"
else if dateMonthNumber == 12 dateMonth = "December"
var dateDay = "\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:8)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:9)])"
//Remove 0 from beginning of first 9 days of month (01 becomes 1, 02 becomes 2, etc.)
if dateDay.hasPrefix("0") dateDay = "\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:9)])"
//DELETE cell.detailTextLabel?.text = dateMonth + " " + String(dateDay) + ", " + String(dateYear)
cell.dateLabel?.text = "Date: " + dateMonth + " " + String(dateDay) + ", " + String(dateYear)
//Populate Category
cell.categoryLabel?.text = "Category: " + posts[indexPath.item].category
print("cell called")
return cell
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
//Checks that Web View Segue was Activated
if segue.identifier == "webViewSegue"
// Make sure segue destination can be a Web View Controller
if let destination = segue.destination as? WebViewController
//Get the Index Path for Clicked Cell (so we know which URL in array to grab), set URL in destination WebViewController
let indexPath = self.tableView.indexPathForSelectedRow!.row
destination.urlAddress = posts[indexPath].url
if segue.identifier == "filterSegue"
print("FILTER ACTIVATED")
过滤视图控制器:
import UIKit
class FilterViewController: UIViewController
@IBAction func cancelAction(_ sender: UIBarButtonItem)
_ = navigationController?.popViewController(animated: true)
dismiss(animated: true, completion:nil)
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view.
var titleView: UIImageView
titleView = UIImageView(frame:CGRect(x: 0, y: 0, width: 50, height: 60))
titleView.contentMode = .scaleAspectFit
titleView.image = UIImage(named: "860logo.png")
self.navigationItem.titleView = titleView
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
//Checks that Web View Segue was Activated
if segue.identifier == "setFilterSegue"
// Make sure segue destination can be a Web View Controller
if let destination = segue.destination as? TableViewController
//Get the Index Path for Clicked Cell (so we know which URL in array to grab), set URL in destination WebViewController
destination.numPosts = 3
destination.tableView.reloadData()
_ = navigationController?.popViewController(animated: true)
dismiss(animated: true, completion:nil)
【问题讨论】:
self.tableView.reloadData()
inside viewDidLoad()
只被调用一次
【参考方案1】:
首先这两行是多余的:
self.tableView.reloadData()
tableView.reloadData()
删除第一个。
第二次移动该行以将表格视图重新加载到viewWillAppear
。不像 viewDidLoad
只调用一次 viewWillAppear
会在视图显示时被多次调用。
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
tableView.reloadData()
最后你创建日期字符串的方式真的很可怕。还有一种更方便的方法。
替换
//Format Date String, Set Cell's Date Text
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let stringDate = dateFormatter.string(from:posts[indexPath.item].date)
let dateYear = "\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:0)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:1)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:2)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:3)])"
let dateMonthNumber = Int("\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:5)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:6)])")
var dateMonth = ""
if dateMonthNumber == 01 dateMonth = "January"
else if dateMonthNumber == 02 dateMonth = "February"
else if dateMonthNumber == 03 dateMonth = "March"
else if dateMonthNumber == 04 dateMonth = "April"
else if dateMonthNumber == 05 dateMonth = "May"
else if dateMonthNumber == 06 dateMonth = "June"
else if dateMonthNumber == 07 dateMonth = "July"
else if dateMonthNumber == 08 dateMonth = "August"
else if dateMonthNumber == 09 dateMonth = "September"
else if dateMonthNumber == 10 dateMonth = "October"
else if dateMonthNumber == 11 dateMonth = "November"
else if dateMonthNumber == 12 dateMonth = "December"
var dateDay = "\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:8)])\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:9)])"
//Remove 0 from beginning of first 9 days of month (01 becomes 1, 02 becomes 2, etc.)
if dateDay.hasPrefix("0") dateDay = "\(stringDate[stringDate.index(stringDate.startIndex, offsetBy:9)])"
//DELETE cell.detailTextLabel?.text = dateMonth + " " + String(dateDay) + ", " + String(dateYear)
cell.dateLabel?.text = "Date: " + dateMonth + " " + String(dateDay) + ", " + String(dateYear)
与
//Format Date String, Set Cell's Date Text
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = dateFormatter.date(from: posts[indexPath.item].date)!
dateFormatter.dateFormat = "MMMM d, yyyy"
cell.dateLabel?.text = "Date: " + dateFormatter.string(from:date)
【讨论】:
非常感谢您的反馈。我尝试了 viewWillAppear,但是没有从 FilterViewController 更新 numPosts。所以destination.numPosts = 3 不起作用。在 viewWillAppear 中,我包含了一个 print(numPosts),它仍然输出 10。所以基本上,正在调用 cellForRowAt,但是它仍然没有重新加载包含三个帖子的表格。numPosts
不影响显示多少帖子。您必须更改posts
中的项目数。
再次感谢您,您的回复非常全面和有帮助。我尝试使用帖子数组计数,而不是 numPosts。在FilterViewController 中,我添加了一些代码来直接更改posts 数组。它看起来像这样:destination.posts.removeAll()。然后我创建 3 个新帖子并将它们附加到数组中。但是在tableViewController 的viewWillAppear 函数中,它仍然显示posts.count 是10。你知道为什么这不会更新吗?奇怪的是再次调用viewDidLoad 并且它具有正确的posts 编号。 viewWillLoad 没有。
viewDidLoad
应该被调用一次,除非你使用额外的 nib 文件。【参考方案2】:
您必须手动调用 tableView.reloadData()。目前你只在 viewDidLoad() 中调用它,这意味着它只会在视图加载时被调用。
另一个想法是在 viewDidAppear() 中调用它,如果您正在修改另一个视图中的数据(并且该视图尚未卸载)。
【讨论】:
【参考方案3】:viewDidLoad 仅在最初加载视图时调用一次(例如,从情节提要中)
如果您希望每次显示视图时都发生一些事情,请使用 viewWillAppear 或 viewDidAppear。
以下两行代码做同样的事情:
self.tableView.reloadData()
tableView.reloadData()
注意:tableView.reloadData 必须在主线程上调用。 您可能必须按如下方式包装对 reloadData 的调用:
// for Swift 3
DispatchQueue.main.async
self.tableView.reloadData()
【讨论】:
以上是关于未使用 reloadData() 方法调用 cellForRowAt indexPath的主要内容,如果未能解决你的问题,请参考以下文章
未调用 tableView reloadData cellForRowAtIndexPath
在 UICollectionView 上调用 reloadData 后 contentSize 未更新
cellForRowAtIndexPath:reloaddata 未调用
在 swift uiTableView 中调用 reloadData() 后,旧项目剩余,新项目未显示
使用 UITableView 的可变高度自定义单元格调用 reloadData 时保持 UITableView 的当前位置