cellForRowAt indexPath is not being called with re

2019-06-10 01:05发布

In Swift 3, I am trying to create a "Filter" view that lets the user filter posts in a table view by category and by date. Currently, the filter view is presented modally and is dismissed when you click "Done".

I have not set up the date/category functionality yet. First, I am just trying to get the tableView to update to show only 3 of the posts rather than 10. To do this, I set destination.numPosts = 3 in my FilterViewController.

Using print statements, it can be seen that the TableViewController does in fact update its posts array in the viewDidLoad function to have 3 posts. The numberOfRowsInSection gets called and is correct. The numberofSections always returns 1. In viewDidLoad, I tried self.tableView.reloadData() and tableView.reloadData() however, cellForRowAt indexPath only gets called when you initially run the app and it does not call this when the data is reloaded.

Any ideas on how I can repopulate the table of posts when the FilterViewController is dismissed?

Table View Controller:

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")
    }
}
}

Filter View Controller:

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)
        }
    }
}
}

3条回答
淡お忘
2楼-- · 2019-06-10 01:32
  • First of all these two lines are redundant:

    self.tableView.reloadData()
    tableView.reloadData()
    

    Delete the first one.

  • Secondly move the line to reload the table view into viewWillAppear. Unlike viewDidLoad which is called only once viewWillAppear is called multiple times whenever the view is going to be displayed.

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData()
    }
    

Finally your way to create the date string is really terrifying. There is a much more convenient way.

Replace

//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)

with

//Format Date String, Set Cell's Date Text
let dateFormatter = DateFormatter()
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)
查看更多
神经病院院长
3楼-- · 2019-06-10 01:40

viewDidLoad only gets called once when the view is initially loaded (e.g. from a Storyboard)

If you want something to happen every time the view is shown, use viewWillAppear or viewDidAppear.

The following two lines of code do the same thing:

self.tableView.reloadData()
tableView.reloadData()

Note: tableView.reloadData has to be called on the main thread. You MAY have to wrap the call to reloadData as follows:

// for Swift 3
DispatchQueue.main.async {
    self.tableView.reloadData()
}
查看更多
小情绪 Triste *
4楼-- · 2019-06-10 01:43

You have to call tableView.reloadData() manually. Currently you are only calling it in viewDidLoad() which means that it will be called only when the view is loaded.

Another Idea would be to call it in viewDidAppear() if you are modifying the data in another view (and the view has not been unloaded).

查看更多
登录 后发表回答