I'm trying to build a uitableviewcontroller and am having difficulty dealing with swift 3. Whenever the numberOfRowsInSection gets called, it gets called 4 times and then the app crashes. Does anyone know how to implement this is swift 3?
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6;
}
There are 6 items in the array that I want to populate the table with. I printed the array count to confirm. this is the full view controller.
class PCRInpatientsViewController: UITableViewController
{
var listInpatient = [PCRPatient]();
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated);
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none;
self.title = "Inpatients";
let view = self.view.frame;
let background = UIView(frame: view);
background.backgroundColor = Constants.medisasDarkGrey;
self.tableView.backgroundView = background;
self.definesPresentationContext = true;
getPatients();
createUI();
}
func getPatients() {
var array = [PCRPatient]();
let i = Patients.sharedInstance.patients
for int in 0..<i.count {
let d = i[int];
if d.status == PCRPatientStatus.PreAdmit {
print(d.name)
array.append(d);
}
}
print(array.count);
self.listInpatient = array;
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated);
}
func createUI (){
self.navigationController?.navigationBar.barTintColor = Constants.medisasRed;
self.navigationController?.navigationBar.isTranslucent = false;
self.navigationController?.navigationBar.tintColor = UIColor.white();
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white()];
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6;
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> PCRCustomCell {
let patient = listInpatient[indexPath.row];
print("sjddsodkso \(patient.name)");
let cell = PCRCustomCell(reuse: "Inpatient", patient: patient);
cell.contentView.backgroundColor = Constants.medisasGrey;
return cell;
}
}
A couple syntax changes in Swift 3 that you need to incorporate. Xcode 8 beta will often suggest the correct fixes to your code but not always. I wrestled with this before finding out that you can check the updated documentation in Xcode 8 beta by hitting Shift + Command + 0 and searching for the first few characters of almost anything. In this case, search for UITableViewDataSource and you'll see everything I'm about to note.
1) cellForRowAtIndexPath is now cellForRowAt. NSIndexPath is now IndexPath. Implement like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// if you use prototype cells
let cell = tableView.dequeueReusableCell(withIdentifier: "prototypeCellIdentifier") as! CustomUITableViewCell
// configure your cell
return cell
}
2) heightForRowAtIndexPath is similarly now heightForRowAt. I haven't implemented this personally but but from the docs it's implemented like this:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return float
}
3) As others noted, numberOfRowsInSection should be dynamic, but I don't believe it's causing the crashes.
Related
I have a view controller, in the viewdidload method I call a function to make some calls to retrieve data online.
After I retrieve the data I append them into an array and reload the table view
at first, everything looks great however, when I scroll down I get to see what you see down below.
extension CastTableViewController : UITableViewDelegate, UITableViewDataSource {
func conigure_cast_table () {
castTable.translatesAutoresizingMaskIntoConstraints = false
castTable.delegate = self
castTable.dataSource = self
castTable.register(ActorCell.self, forCellReuseIdentifier: ActorCell.cellid)
view.addSubview(castTable)
castTable.frame = view.bounds
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cast.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = castTable.dequeueReusableCell(withIdentifier: ActorCell.cellid, for: indexPath) as! ActorCell
let name = cast[indexPath.row].name
let character_name = cast[indexPath.row].character
let pic = cast[indexPath.row].picture_path
cell.configure(name: name, charName: character_name, pic_url: pic)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
i fixed this by using prepareforreuse
// in the custom cell class
override func prepareForReuse() {
super.prepareForReuse()
for subview in stack.arrangedSubviews {
stack.removeArrangedSubview(subview)
}
actorPic.image = nil
realName.banner_title.text = nil
realName.info.text = nil
character.banner_title.text = nil
character.info.text = nil
}
I not find what is my problem.
I need to give space between one cell and another.
I wrote self.tableView Storyline.delegate = self because I read that this could be the problem, but not know if it is correct.
This is my code:
class ClassName: UIViewController, UITableViewDataSource, UITabBarControllerDelegate, UITableViewDelegate {
public var notifications: [APINotification] = []
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
tableViewStoryline.rowHeight = UITableViewAutomaticDimension
tableViewStoryline.estimatedRowHeight = 140
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
self.notifications = []
self.getLastNotifications()
APIAuth.shared.count_badge = 0
self.tabBarController?.tabBar.items![0].badgeValue = nil
}
public func getLastNotifications() {
let req = Notification()
req.getLastNotifications(onComplete: {events in
self.notifications = events
DispatchQueue.main.async(execute: {
self.tableViewStoryline.delegate = self
self.tableViewStoryline.dataSource = self
self.tableViewStoryline.sectionHeaderHeight = 10
self.tableViewStoryline.reloadData()
})
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// There is just one row in every section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.notifications.count > 4 {
return 4
} else {
return self.notifications.count
}
}
// Set the spacing between sections
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell = tableView.dequeueReusableCell(withIdentifier: "controller")! as UITableViewCell
titleLbl.text = notifications[indexPath.row].title
bodyLbl.text = notifications[indexPath.row].description
typeLbl.text = notifications[indexPath.row].type
return cell!
}
}
Does anyone have any idea what the problem is?
Is there some code missing?
Thanks!
I think this is what you want:
func numberOfSections(in tableView: UITableView) -> Int {
if self.notifications.count > 4 {
return 4
} else {
return self.notifications.count
}
}
// There is just one row in every section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
Then you have to change also cellForRowAt to take this into account.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell = tableView.dequeueReusableCell(withIdentifier: "controller")! as UITableViewCell
titleLbl.text = notifications[indexPath.section].title
bodyLbl.text = notifications[indexPath.section].description
typeLbl.text = notifications[indexPath.section].type
return cell!
}
Instead of having one section with notifications.count rows, you want notifications.count sections and each section with one row. Now setting 10 points as height for section header will make cells appear as having spaces between them.
There are some other options that you can consider, see my other answer.
you are using wrong delegate function.
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
is used for the hieght of header not for height of cell.
use func tableView(UITableView, heightForRowAt: IndexPath)
you will get correct sized cells.
Hope this helps!
I have an imageView in my custom table view cell. I have multiple images copied to Xcode.
Now I need to display these images in the tableview cell. I have decalared a leaderImage variable in which I have given the image names.
How can I achieve this?
This is what I have:
var leaderImage : [String]!
override func viewDidLoad() {
self.leadername = ["Oomen Chandy","PC.George","Veena George","M.Mukesh"]
self.areaName = ["Puthupally","Poonjar","Thrissur","Kollam"]
self.approvalrate = ["98%","94%","88%","95%"]
self.leaderImage = ["rahul","Anil","Manu",]
leadTableSetup()
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func leadTableSetup(){
LeadTableView.delegate = self
LeadTableView.dataSource = self
self.LeadTableView.register(UINib(nibName: "LeaderBoardTableViewCell", bundle: nil), forCellReuseIdentifier: "leadCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return leadername.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "leadCell") as! LeaderBoardTableViewCell
cell.leaderNameLbl.text = leadername[indexPath.row]
cell.areaLbl.text = areaName[indexPath.row]
cell.approvalLabel.text = approvalrate[indexPath.row]
cell.imageView = leaderImage[indexPath.row]
return cell
}
In cell cellForRowAt method
cell.imageView.image = UIImage(named: leaderImage[indexPath.row])
In your self.leadername contains 5 element but rest of all your array contains 4 or 3 element that's why you have problem occur.
To avoid Crash
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return leaderImage.count
}
I'm trying to display a section header with the month and year the cell was created as the text in the section header. This is my code but it only displays one section header like so. Any idea why and how I can get it to display the year and month the cell was created?
import UIKit
class PRViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tblTasks : UITableView!
//For persisting data
let defaults = NSUserDefaults.standardUserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
self.tblTasks.reloadData()
tblTasks.registerNib(UINib(nibName: "PRTableViewCell", bundle: nil), forCellReuseIdentifier: "PRTableCell")
tblTasks.tableFooterView = UIView()
}
override func viewWillAppear(animated: Bool) {
self.tblTasks.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return 1
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Your PR's"
}
//Define how our cells look - 2 lines a heading and a subtitle
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let identifier = "PRTableCell"
var cell: PRTableViewCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? PRTableViewCell
if cell == nil {
tableView.registerNib(UINib(nibName: "PRTableViewCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? PRTableViewCell
}
// Assign the contents of our var "items" to the textLabel of each cell
// cell.textLabel!.text = taskMgr.tasks[indexPath.row].name
// cell.detailTextLabel!.text = taskMgr.tasks[indexPath.row].desc
cell.PRLabel.text = taskMgr.tasks[indexPath.row].name
cell.NotesLabel.text = taskMgr.tasks[indexPath.row].desc
cell.WeightLabel.text = taskMgr.tasks[indexPath.row].weight + "lb"
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath){
if (editingStyle == UITableViewCellEditingStyle.Delete){
taskMgr.removeTask(indexPath.row)
tblTasks.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
let numberOfSections = taskMgr.tasks.count
return numberOfSections
}
}
Here's one way to do it. Note that this code assumes your cell data is in an array called "cellArray". It displays a date that starts with today and goes back one day for each section. Obviously you'll need to substitute your dates.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.cellArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath)
// TODO: configure cell for display using self.cellArray[indexPath.section]
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let df = NSDateFormatter()
df.dateStyle = .MediumStyle
df.timeStyle = .NoStyle
// TODO: determine the actual date
let displayDate = NSDate().dateByAddingTimeInterval(Double(section * -86400))
return df.stringFromDate(displayDate)
}
So example code is below (code not tested obviously). I have assumed that there is a dateCreated property containing an NSDate in the objects held in your tasks array.
Example code:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let formatter = NSDateFormatter() // This is slightly inefficient for a large number of rows because setting up NSDateFormatter is expensive. You could make this a property.
formatter.dateStyle = .ShortStyle
formatter.timeStyle = .NoStyle
let sectionHeaderDate = taskMgr.tasks[section].dateCreated
let dateString = formatter.stringFromDate(sectionHeaderDate)
return dateString
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = "PRTableCell"
var cell: PRTableViewCell! = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath:idx) as? PRTableViewCell // You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method (http://stackoverflow.com/q/12737860/558933).
cell.PRLabel.text = taskMgr.tasks[indexPath.row].name
cell.NotesLabel.text = taskMgr.tasks[indexPath.row].desc
cell.WeightLabel.text = taskMgr.tasks[indexPath.row].weight + "lb" // Note iOS 9 allows you to localise weights rather than hard-coding "lb" or "kg". You should look at the documentation.
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = taskMgr.tasks.count
return numberOfSections
}
To add a new "section" to the UITableView you must add the new data to the array taskMgr.tasks and then either reload the table or update just the added rows. Wrap these lines of code in tblTasks.beginUpdates and tblTasks.endUpdates. Similarly for deleting.
I have a UITableView, and added it as a subview of a UIView.
Whenever I select a cell that had everything disappears in UITableView.
Already had this problem at other times, however it stopped happening without changes on code.
Currently I use Swift, however already happened in Objective-C.
Code:
TableView delegates:
numberOfSectionsInTableView
numberOfRowsInSection
cellForRowAtIndexPath
heightForRowAtIndexPath
didSelectRowAtIndexPath
Also registered the identifier of the cell
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
listObjectsToList = ["String 1","String 2","String 3"]
self.view.frame.size = CGSizeMake(300, 110)
self.view.layer.cornerRadius = 5
self.view.layer.masksToBounds = true
self.tableView.scrollEnabled = false
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listObjectsToList.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell
cell.textLabel.text = listObjectsToList.objectAtIndex(indexPath.row) as? String
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 40
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
let objectSelected: AnyObject = listObjectsToList.objectAtIndex(indexPath.row)
object.type = objectSelected as String
self.view.removeFromSuperview()
}
However the method didSelectRowAtIndexPath is not called...
Code adding tableview:
var listTypeTableViewController = ListTypeTableViewController()
listTypeTableViewController.view.frame = CGRectMake(10, 80, 300, 130)
self.view.addSubview(listTypeTableViewController.view)
I have tried:
var listTypeTableViewController = ListTypeTableViewController()
listTypeTableViewController.view.frame = CGRectMake(10, 80, 300, 130)
self.view.addSubview(listTypeTableViewController.tableView)
But without success
The problem was and I was just trying to extract the UITableView to show it. When I need to add a UITableViewController as a child of my UIViewController:
var listTypeTableViewController = ListTypeTableViewController(nibName: "TableViewTypeScheduling", bundle: nil)
listTypeTableViewController.view.frame = CGRectMake(10, 80, 300, 130)
addChildViewController(listTypeTableViewController)
view.addSubview(listTypeTableViewController.view)
The reason is this line in tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) method:
self.view.removeFromSuperview()
You remove a view and all of its superviews, including the table view.