In my conception every row of tableview is kind of task which you can fill in.And every time you open the app one row should be a priori on a tableView. (As you see in picture )
Also I have button which allows you to add a row.
But I have no idea how can I know the number of rows in section.
Can you please help me with it ?(In my code I've commented the moments I can't understand)
class TaskSecondViewController: UIViewController,UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
self.tableView.separatorColor = UIColor.clear
#IBAction func insert_rows(_ sender: Any) {
let indexPath = IndexPath(row: 1, section: 1) // Don't know what to write in "row"
self.tableView.insertRows(at: [indexPath], with: .top)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1 // Here also
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TaskTableViewCell
return cell
}
}
have you tried this :
yourTableView.numberOfRows(inSection: 0)
this returns the no of rows in your table view's section
You can simply have
var numOfRow = 0
every time you hit the button
numberOfRow += 1
tableView.reloadData()
so you can return numberOfRow
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numOfRow
}
But I have no idea how can I know the number of rows in section.
The important thing to understand is that a table knows nothing about the items it displays, or how to display them, or what to do when people interact with them. A table is really just a list of sections, where each section is a list of cells. And it can scroll. And it can ask for help.
The items that are displayed are kept elsewhere. They don't even exist as rows in the table all at the same time. The table only keeps as many rows as it needs to display, and when the user scrolls, it asks some other object for more rows to display and throws out the rows that are no longer displayed. That other object is the data source, and it may be the 'elsewhere' where the items are kept, or it may only be an object that knows where to find (or generate) those items.
In this case, your TaskSecondViewController view controller is the table's data source. You need make sure that that controller somehow has access to the data it needs. Maybe it reads the list from a file. Maybe an array of items is passed in from some other object. There are a million variations on the theme, but it's up to you to know what you want to display in the table and to know where those things are kept. Once you know that, you should be able to figure out how many items are in a given section. You're also going to need to know how many sections there are. It could be that you just have one list of items, and you don't plan to break it up into sections; in that case, you'll just return 1 for the number of sections and the number of items in the whole list for the number of rows in that section.
If you just want to add a row, you don't have to insert it into the table view at an explicit spot. It would be easier to have an array (or dictionary or whatever) and add your items into that object, and then reload your table view when items are added.
var itemsToDisplay = [SomeObject]
override func viewDidLoad() {
// populate items if needed
}
#IBAction func insert_rows(_ sender: Any) {
// get your data to create your object
// add your object to itemsToDisplay
itemsToDisplay.append(myObject)
// for a TableViewController
self.tableView.reloadData()
// if you've included the tableView as an #IBOutlet
myTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsToDisplay.count // this might be zero, but it doesn't matter
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TaskTableViewCell
var item = itemsToDisplay[indexPath.row]
cell.titleLabel.text = item.whatever
return cell
}
Related
I am currently making a golf round tracker that displays your rounds in a table view with the cells being xibs. When I add one round, it appears fine on the table view, but when I add another round it adds that cell and doubles the cells. Here is a picture of what happens: https://i.stack.imgur.com/SOgN4.png. Here is my code:
class RoundDisplay: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
arrayOfCellData.append(roundData(id : arrayOfCellData.count + 1, date : datePlayedFC, course : currentCourse, score : String(score1234) ))
tableView.reloadData()
print(arrayOfCellData)
}
override func numberOfSections(in tableView: UITableView) -> Int {
//Shows how many cells it should display; number of current cells
return arrayOfCellData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//Shows how many cells it should display; number of current cells
return arrayOfCellData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Defines what xib to use for cells
let cell = Bundle.main.loadNibNamed("TableViewCell", owner: self, options: nil)?.first as! TableViewCell
//Adds array data to each cell
cell.DateLbl.text = arrayOfCellData[indexPath.row].date
cell.CourseName.text = arrayOfCellData[indexPath.row].course
cell.ScoreLbl.text = arrayOfCellData[indexPath.row].score
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//Shows how high to make cells; height of xib
return 68
}
}
The number of sections function needs to be set to one. I realized that it decided how many cells it should show for the data from the array. Which means if you have the function set as I did, for instance, if you had two sets of data in the array, it would put two cells for each data. Thanks to #Magnas and #vacawama for the help!
After much searching and reading I unfortunately do not come from the following. I want to use static tables to display certain data. (Are there better options?)
In my view I first put an onion picture with a container view underneath. The container view again refers to a Table View Controller.
I made an outlet from the cells and then I thought I could easily adjust the text.
Now I want to change the text of the fields in the table, but unfortunately I do not succeed.
When I start the app then the table is completely empty as seen on the screenshot.
What am I doing wrong ?
class TableViewController: UITableViewController {
var data: [String] = ["Muis", "Aap", "Koe", "Vis"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let iets = data[indexPath.row]
cell.textLabel?.text = iets
return cell
}
}
If you want to use static cells
Forget dequeueing UITableViewCell instances and all tableview data source and delegate methods.
In Interface Builder select the table view and select Static Cells from the Content popup
Drag the amount of static cells you need into the canvas
In the view controller declare IBOutlets and connect them directly to the UI elements in the cells
You need to change your way of thinking for this one. You do not own the cells, the UITableView does. It will provide cells as it seems fit by using your implementations of UITableViewDataSource:
func numberOfSections(in: UITableView) -> Int
func tableView(UITableView, numberOfRowsInSection: Int) -> Int
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
Normally, the texts (your actual data) would be held in a list available to this data source.
Example:
var data: [String] = []
// Other functions
func numberOfSections(in: UITableView) -> Int {
return 1
}
func tableView(UITableView, numberOfRowsInSection: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YOUR_IDENTIFIER")
cell.text = data[indexPath.row]
return cell
}
Now, if you want to change this cell's text, all you have to do is update your data list and reload the data.
What I have done after a lot of testing and reading. I have create a segue to the statutable class.
if (segue.identifier == "myEmbeddedSegue") {
let childViewController = segue.destination as! hondDetialTableViewController
childViewController.hondId = hondData["hondId"]!
}
In this segue I send only the hondId, everything else i ask entities.
I'm sorry but this is not at all how UITableView works. The UITableViewCell that you define in the Xib/Storyboard within the tableview are just "models" or templates, they don't actually exists until you dequeue them.
You can read how UITableView works here: http://www.thomashanning.com/uitableview-tutorial-for-beginners/
You have to return numberOfSections > 0 if you want anything displayed in your tableview; similarly, that section has to also have numberOfRows > 0 otherwise again, nothing will be displayed (ok, maybe headers and footers if those are properly setup).
At any rate, cells are only accessible after you dequeue them. Creating an outlet in a XIB to a UITableViewCell is useless in most cases.
You can explore other options, such as UIStackView, or maybe what you need is just plain custom UIView with labels that you properly set and layout using NSLayoutConstraints. There are plenty of resources out there, this is just one I quickly Googled for you to get started: https://www.youtube.com/watch?v=de0sthle44I
Good Luck.
Loading all the date from the firebase to the tableview at a time but i wanted to load 10 items at a time when i scroll to bottom again 10 items should load to the tableview, below is my code
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "inciCell") as!
IncidentCell
cell.delegate = self
cell.setupCell(with: item, indexPath)
return cell
}
}
In the delegate method cellForRowAtIndexPath you may check something like indexPath.row == items.count - 1.
if it's true, then you get 10 items from your DB and append it to your `items.
then do tableView.reloadData() to update the table view with 10 new items.
You may also make some nice spinner in the bottom (tableFooterView) of the table view. But it could be the next step.
Hope it helps.
I have a UITableView set up that works almost correctly, but if you scroll all the way up or down rather quickly, it shuffles the cells out of order. I set the label to reflect the index path and even when it starts out
[0,0] [0,1] [0,2] [0,3] [0,4] [0,5] [0,6]
After a quick few swipes up and down, the cells look like this
[0,1] [0,6] [0,2] [0,3] [0,4] [0,5] [0,0] [0,1]
My code is similar to the following
import UIKit
class TableViewController : UITableViewController {
var dates: [Date]?
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dates?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCell.storyboardID, for: indexPath) as? tableViewCell else { fatalError() }
let date = dates?[indexPath.row]
cell.date = date
cell.delegate = self
cell.cellIndex = indexPath
return cell
}
}
From Apple docs on UITableView
When the table view asks the data source to configure a cell object for display, the data source can access the queued object by sending a dequeueReusableCellWithIdentifier: message to the table view, passing in a reuse identifier. The data source sets the content of the cell and any special properties before returning it. This reuse of cell objects is a performance enhancement because it eliminates the overhead of cell creation.
So in this case, you are storing the value of indexPath in the cell propeties, "cellIndex", which is reusable by other cells. Therefore, it will randomly show the value based on previously assigned in queue.
In order to encounter this, you can either store the value to array variable in viewController, so every time the datasource want to re-create the cells, it will get from the array consistently.
Secondly, you can directly assign the indexPath to the cell ui element such as UILabel.
cell.titleLabel.text = "\(indexPath)"
I have a tableview inside my UIViewController to display comments. The height of this tableview depends on the number and the size of comments. The cells are dynamic.
I use autolayout, so my tableview has a height constraint. I set this constraint programmatically :
override func viewDidLayoutSubviews() {
self.heightCommentsTableView.constant = self.commentsTableView.contentSize.height + 50
}
It works if I display all the comments at once.
BUT, I would like display the comments 5 per 5, using this method : load more for UITableView in swift because of performance issue to display my view
(all my comments are loaded before pushing the view)
I noticed when I set my constraint, it calls cellForRowAtIndexPath for all the comments, not only the first 5.
I don't know how to do.
EDIT
var allCommentsArray: NSMutableArray = []
var elements: NSMutableArray = []
var range = 5
var currentPage = 0
var nextpage = 0
override func viewDidLoad() {
super.viewDidLoad()
allCommentsArray = NSMutableArray(array: comments)
elements.addObjectsFromArray(allCommentsArray.subarrayWithRange(NSMakeRange(0, range)))
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
self.nextpage = self.elements.count - 5
if indexPath.row == nextpage {
self.currentPage++
self.nextpage = self.elements.count - 5
self.elements.addObjectsFromArray(self.allCommentsArray.subarrayWithRange(NSMakeRange(self.currentPage, self.range)))
tableView.reloadData()
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CommentCustomTableViewCell", forIndexPath: indexPath) as! CommentCustomTableViewCell
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
The table view will call tableView(_:cellForRowAtIndexPath:) for every visible cell it is about to create, the amount of it will determine based on how many sections and how many cells in each section. You let the table vie know these amounts by implementing the tableView(_:numberOfRowsInSection:) and numberOfSectionsInTableView(_:) methods of UITableViewDataSource. So, if you want to control how many cells could possibly be created and visible at a given time, you'd have to manage that state in your data source by adding and removing according to whatever logic you desire. In the answer that you linked, you can see that he is called elements.addObjectsFromArray to progressively add more elements in batches.