I have set up tableview many times but don't why is not it showing anything. I have added a tableview on my storyboard file, added reference on ViewController file and set datasource and delegate on storyboard. on viewDidLoad registered the cell and finally added reusableIdentifier on TableViewCell. Here is my code with details configuration :
import UIKit
struct ViewControllerConstants {
static let kCellIdentifier = "TableViewCell"
static let kNibName = "TableViewCell"
}
class ViewController: UIViewController {
var cellImageNames : [String] = ["image1","image2","image3","image4","image5","image6"]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tableView.register(UINib.init(nibName: ViewControllerConstants.kNibName, bundle: nil), forCellReuseIdentifier: ViewControllerConstants.kCellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
self.tableView.reloadData()
}
}
extension ViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellImageNames.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: ViewControllerConstants.kCellIdentifier, for: indexPath) as? TableViewCell {
cell.contentImageView.image = UIImage.init(named: cellImageNames[indexPath.row])
return cell
}
return UITableViewCell.init()
}
}
extension ViewController : UITableViewDelegate {
}
Try to remove identifiers for cells in storyboard.
Problem: Cell height was not defined on code. So it was creating cell with 0 height value .
Solution: Need to specify height of each row as below code:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
Related
I have this code:
class UserProfilViewController: UIViewController {
// Outlets
#IBOutlet weak var userProfileTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.title = "Profil"
}
}
// MARK: - Table View Data Source
extension UserProfilViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserProfilCell", for: indexPath)
return cell
}
}
My project in bitbucket: https://bitbucket.org/trifek/karta-nauka/src/master/
I placed one tableviewcell cell on the tableview (UserProfil.storyboard). I have a form on it that I would like to display in this cell. The problem is the cell does not display. Does anyone know how to fix it?
As per the code you have shared, Please change your code to following.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserProfilCell", for: indexPath) as! UserProfilTableViewCell
return cell
}
Let me know in case of any queries.
IMHO, first try to clear your requirements. If you want to display fix number of cells then you can simply use static cells. If your cells are dynamic i.e their number depends on some calculation or other logic, then you can use dynamic cell. While using dynamic cell, verify if you have registered it or not (if you are using xib for cell) and also verify for the cell identifier.
#Lukasz
Please use the below code for this.
class UserProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setUIComponents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func setUIComponents(){
registerNibs()
}
}
extension UserProfileViewController: UITableViewDelegate, UITableViewDataSource{
internal func registerNibs(){
tableView.register(UINib(nibName: String(describing: UserProfileTableCell.self), bundle: Bundle.main), forCellReuseIdentifier: kUserProfileCellReuseId)
}
//MARK: TableView Methods -
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sessionCell: UserProfileTableCell.self = tableView.dequeueReusableCell(withIdentifier: kUserProfileCellReuseId, for: indexPath) as! UserProfileTableCell.self
cell.titleLabel.text = “TEST”
return sessionCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
class UserProfileTableCell: UITableViewCell {
//Set the "kUserProfileCellReuseId" in nib to register identifier.
let kUserProfileCellReuseId = "kUserProfileCellReuseId"
//MARK: - Override Methods
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUIComponents()
}
private func setUIComponents(){
}
}
You never declare that your view controller conforms to the UITableViewDataSource or UITableViewDelegate protocols. Given that you don't do that, you would not be able to set your view controller as the data source or delegate of your table view.
So I have a UISplitViewController and in the DetailView I have a UITableView.
What I want to do is take the selected cell from the root view controller and append it to the string which is populating my tableview in the detail view controller. I can append with selection very easily but I need help with is the updating part.
What's supposed to happen is when you click the cell, it appends the value in the cell to the global variable main.BoatManifest, and then update the table. I just don't know how to do that.
Here's some code:
import UIKit
class DetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FullListCellDelegate {
#IBOutlet weak var tableView: UITableView!
func updateName(sender: FullListCell, detVC: DetailViewController) {
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return main.BoatManifest.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
cell.textLabel?.text = main.BoatManifest[indexPath.row]
return cell
}
}
struct Main {
var BoatManifest: [String] = []
}
var main = Main(BoatManifest: [" "])
This is the code for my detail view and the struct Main on the bottom is just a global variable. My MainView code is this:
import UIKit
protocol NameSelectionDelegate: class {
func nameSelected()
}
class MasterViewController: UITableViewController {
var Names: [String] = ["John", "Mark", "Paul", "Jeremy"]
override func viewDidLoad() {
super.viewDidLoad()
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 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 Names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = Names[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
main.BoatManifest.append(Names[indexPath.row])
NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)
}
func loadList(){
//load data here
self.tableView.reloadData()
}
}
I attempted to use a UISplitViewController tutorial to figure it out but it didn't have the tableview in the detail view controller. I need to send a message when I select the cell to the detail tableview and have it update with the appended text.
Thanks for your help.
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 6 years ago.
I'm new to Swift. I have two table view controllers, one with static cells and one with dynamic ones. I basically want to let a user select his marital status on the second table view controller and send his choice back to the first table view controller (and display his selection on the cell "Marital Status"). Here is a screenshot of my storyboard:
Storyboard
Current code on second table view controller:
import UIKit
class SecondTableViewController: UITableViewController {
let maritalStatusArray: [String] = ["Single", "Married"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return maritalStatusArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MaritalStatusCell", for: indexPath)
cell.textLabel?.text = maritalStatusArray[indexPath.row]
return cell
}
}
My guess is that I have to add a segue from the dynamic cell of the second view controller back to the first one. Is that right ?
Supposing this is the way to do it, I have afterwards to update the text of the static label to include the choice made by the user. Any ideas ?
There few ways by which you can implement the callback functionality to pass data.
Delegate
Using Block CallBack
Post Notification
But I would suggest to use delegate which is best way, Post Notification is also a way but I do not want to prefer.
You can use custom delegate to do this:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SecondViewControllerProtocol {
#IBOutlet weak var userInfoTableView: UITableView!
var userInfoArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
userInfoArray = ["Marital Status","Canton","Commune","Religion"]
self.userInfoTableView?.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let userInfoCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
userInfoCell.textLabel?.text = userInfoArray[indexPath.row]
if indexPath.row == 0{
userInfoCell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
}
return userInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewControllerIdentifier") as! SecondViewController
secondVC.statusDelegate = self
self.navigationController?.present(secondVC, animated: true, completion: nil)
}
}
func changeMaritalStatus(type: String){
let maritalStatusCell = userInfoTableView.cellForRow(at: IndexPath(row:0 , section:0))
maritalStatusCell?.textLabel?.text = String("Marital Status: \(type)")
}
}
SecondViewController.swift:
import UIKit
protocol SecondViewControllerProtocol {
func changeMaritalStatus(type: String)
}
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var maritalStatusTableView: UITableView!
var maritalStatusArray: [String] = []
var statusDelegate : SecondViewControllerProtocol? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
maritalStatusArray = ["Single","Married","Divorced"]
self.maritalStatusTableView.register(UITableViewCell.self, forCellReuseIdentifier: "maritalStatuscell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let maritalStatusInfoCell = tableView.dequeueReusableCell(withIdentifier: "maritalStatuscell", for: indexPath)
let infoLabel: UILabel = UILabel.init(frame: CGRect(x: 10, y: 5, width: 250, height: 50))
infoLabel.text = maritalStatusArray[indexPath.row]
maritalStatusInfoCell.addSubview(infoLabel)
return maritalStatusInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
statusDelegate?.changeMaritalStatus(type: maritalStatusArray[indexPath.row])
self.dismiss(animated: true, completion: nil)
}
}
GitHub link:
https://github.com/k-sathireddy/CustomDelegatesSwift
Output:-
This is a fairly simple question I think. I've separated my UITableView delegate / data sources into their own extensions
//MARK: - UITableView Data Source/Delegate
extension TweetsViewController: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! TweetCell
return cell
}
}
However in the view controller itself I need to set the tblView delegate
class TweetsViewController : UIViewController {
#IBOutlet weak var tblView: UITableView!
var fetchedResultsController : NSFetchedResultsController!
//MARK: View Management
override func viewDidLoad() {
super.viewDidLoad()
tblView.dataSource = self
}
}
However, since the view controller is nor conforming to the protocols but having the extensions handle them, then how do I explicitly set the datasource and delegate for the tableView? Thanks!
You can divide in a extension, as you can check in the apple documentation section about Extensions handling Protocols.
Here I have implement a minimum code doing what you ask, check it out.
import UIKit
class TableViewViewController: UIViewController {
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
}
}
extension TableViewViewController: UITableViewDelegate,UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
cell.textLabel!.text = "it works"
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
}
In Swift 3 and above the table view datasource and delegate methods changed.
import UIKit
class HomeViewController: UIViewController {
#IBOutlet var tblPropertyList: UITableView!
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tblPropertyList.delegate = self
tblPropertyList.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// MARK: - Table View DataSource
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath as IndexPath)
cell.textLabel!.text = "\(indexPath.row) - Its working"
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
}
// MARK: - Table View Delegate
extension HomeViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!)!
print(currentCell.textLabel!.text!)
}
}
the view controller is nor conforming to the protocols but having the extensions handle them
This is incorrect. The extension makes the view controller conformant to the protocols, and the data source and delegate can be set as usual, e.g.: self.tableView.delegate = self
Now in Swift 5.1 you don't need to inherit UITableViewDelegate and UITableViewDataSource
extension HomeViewController {
// MARK: - Table View DataSource
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath as IndexPath)
cell.textLabel!.text = "\(indexPath.row) - Its working"
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
}
// MARK: - Table View Delegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!)!
print(currentCell.textLabel!.text!)
}
}
I am new to swift and am trying to create an app with a table view which can use the view from another UIView controller.
Is it doable?
If so please help me with it, I have attached my code for the main controller below. Please let me know if anything is wrong?
Thank you so much.
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var numbers:[String] = []
let vc = bgViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.backgroundView = vc.view
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(numbers.count == 0){
tableView.backgroundView?.hidden = false
println("1")
}
else{
tableView.backgroundView?.hidden = true
}
return numbers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
return cell
}
}
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var numbers:[String] = []
var vc: bgViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
vc = self.storyboard.instantiateViewControllerWithIdentifier("bgViewController") as! bgViewController
tableView.backgroundView = vc.view
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(numbers.count == 0){
tableView.backgroundView?.hidden = false
println("1")
}
else{
tableView.backgroundView?.hidden = true
}
return numbers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
return cell
}
}
Provide storyboard identifier as bgViewController in attribure inspector.