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)
}
}
}
}
First of all these two lines are redundant:
Delete the first one.
Secondly move the line to reload the table view into
viewWillAppear
. UnlikeviewDidLoad
which is called only onceviewWillAppear
is called multiple times whenever the view is going to be displayed.Finally your way to create the date string is really terrifying. There is a much more convenient way.
Replace
with
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:
Note: tableView.reloadData has to be called on the main thread. You MAY have to wrap the call to reloadData as follows:
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).