Why is table view displayed but cells is not? - ios

I'm builded view like this:
and constrains:
Here is a code:
Main controller
class SelectTagsViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var selectedTagsTableView: UITableView! //added table view
let allTags: [String] = ["Qwerty", "IT", "Manic", "VR", "WishHook", "Books", "Programing", "Aplication", "Something", "Fly", "Swift", "Earth", "Orbit", "Mars", "Summer", "Monkey", "AR", "Space"]
var selectedTags: [String] = ["Qwerty", "IT", "Manic", "VR"]
override func viewDidLoad() {
super.viewDidLoad()
selectedTagsTableView.tableFooterView = UIView(frame: CGRect.zero)
selectedTagsTableView.backgroundColor = .lightGray
selectedTagsTableView.register(SelectedTagCell.self, forCellReuseIdentifier: "SelectedTagCell")
}
}
Extension for tableview
extension SelectTagsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let lable = selectedTags[indexPath.row]
let cell = selectedTagsTableView.dequeueReusableCell(withIdentifier: "SelectedTagCell") as! SelectedTagCell
cell.tagNameLabel.text = lable
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedTags.count
}
}
And class for cells
class SelectedTagCell: UITableViewCell {
#IBOutlet weak var tagNameLabel: UILabel!
#IBOutlet weak var removeTagButton: UIButton!
#IBAction func removeTagButtonTapped(_ sender: Any) {
}
}
But cells aren't displayed:
All code are in one file, and all classes and identifiers are connected to components.
What did I miss?

On the recommendation of #Adrian, I added delegate and datasource below and all now work.
selectedTagsTableView.delegate = self
selectedTagsTableView.dataSource = self
And fixed problem with nil value, removed code below:
selectedTagsTableView.register(SelectedTagCell.self, forCellReuseIdentifier: "SelectedTagCell")

Related

Passing data between a table view cell and a view controller [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 2 years ago.
Right now I have a table view and another view controller. I would like to use the didSelectRowAt function to show a detailed view of the tableview cell on the new view controller. How would I pass data from the the tableview cell to a new view controller? Here is what I currently have.
This is the code for my main view controller.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
struct data {
var sectionTitle = String()
var rowTitles = [String]()
}
var dataArray = [data(sectionTitle: "section 1", rowTitles: ["row 1", "row 2", "row 3"]),
data(sectionTitle: "section 2", rowTitles: ["row 1", "row 2"]),
data(sectionTitle: "section 3", rowTitles: ["row 1"])
]
var searchArray = [(sectionTitle: String, rowTitles: [String])]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchArray[section].rowTitles.count
} else {
return dataArray[section].rowTitles.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell")
if searching {
cell?.textLabel?.text = self.searchArray[indexPath.section].rowTitles[indexPath.row]
} else {
cell?.textLabel?.text = self.dataArray[indexPath.section].rowTitles[indexPath.row]
}
return cell!
}
func numberOfSections(in tableView: UITableView) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if searching {
return searchArray.count
} else {
return dataArray[section].sectionTitle
}
}
}
This is the code for my second view controller so far.
import UIKit
class secondViewController: UIViewController {
#IBOulet weak var nameLabel: UILabel!
#IBOulet weak var descriptionLabel: UILabel!
#IBOulet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func visitButtonTapped(_ sender: Any) {
}
}
Here is my current Storyboard.
Create a model in your ViewController
import UIKit
class secondViewController: UIViewController {
#IBOulet weak var nameLabel: UILabel!
#IBOulet weak var descriptionLabel: UILabel!
#IBOulet weak var imageView: UIImageView!
var titleOfItem : String
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func visitButtonTapped(_ sender: Any) {
}
}
In your tableView delegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Init you secondVC
secondVC.titleOfItem = searchArray[indexPath.section].rowTitles[indexPath.row]
// pushToVC / Present
}

tableview doesn't show anything?

I made sure that my cell identifier was correct I'm not too sure what the problem is. I've been rereading the code on this viewController and I'm not sure if I'm missing something or if there's a specific reason why my tableview isn't loading.
import UIKit
import JGProgressHUD
class BasketViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = footerView
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//MARK: TO DO CHECK IF USER IS LOGGED IN
loadBasketFromFirestore()
}
//MARK: VARS
var basket : basket?
var allItems : [Item] = []
var purchaseItemID : [String] = [] //holds id of items you want to purchase
var hud = JGProgressHUD(style: .dark)
//MARK: IBOUTLETS
#IBOutlet weak var totalPriceLabel: UILabel!
#IBOutlet weak var totalItemsInBasket: UILabel!
#IBOutlet weak var checkOutButton: UIButton!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var footerView: UIView!
//MARK: IBACTIONS
#IBAction func checkOutButtonTapped(_ sender: Any) {}
//something is wrong with
//MARK: DOWNLOAD BASKET
private func loadBasketFromFirestore(){
//MARK: CHANGE 1234 TO A USER ID STRING
downloadBasketFromFirestore("1234") { (basket) in
self.basket = basket
self.getBasketItems()
}
}
private func getBasketItems(){
if (basket != nil) {
print("getting items")
downloadItems(_withIDS: basket!.itemID) { (allItems) in
self.allItems = allItems
self.tableView.reloadData()
}
} else { print("basket is nil")}
}
}
extension BasketViewController : UITableViewDataSource , UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "basketCell", for: indexPath) as! ITEMTableViewCell
cell.generateCellForITEMS(item: allItems[indexPath.row])
return cell
}
}

ios swift tableview not showing custom cells

I am trying to create a table view with custom cells from Storyboard layout in an iOS app.
But for some reason the table cells are not being shown. When I tried to set debug breakpoints I found that the debugger is reaching this function
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
but it never reaches this function -
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
Here is my viewcontroller code -
extension NavigationViewController: UITableViewDataSource, UITableViewDelegate, SideMenuControllerDelegate {
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SideMenuTableItem", for: indexPath as IndexPath) as! SideMenuTableItem
cell.setItemData(items[indexPath.row])
return cell
}
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func setupTableViews() {
menuTable.register(SideMenuTableItem.self, forCellReuseIdentifier: "SideMenuTableItem")
}
}
class SideMenuTableItem: UITableViewCell {
#IBOutlet weak var menuImage: UIImageView!
#IBOutlet weak var menuLabel: UILabel!
var data: MenuItem?
override func awakeFromNib() {
super.awakeFromNib()
}
func setItemData(_ item: MenuItem) {
data = item
menuLabel.text = data?.title
if data?.icon_res != nil {
menuImage.image = UIImage(named: (data?.icon_res)!)
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I have checked in the storyboard that I have set the reusable identifier to the table prototype cell and also connected the datasource and the delegate properties to the tableview
and I am calling the setupTableViews() method inside my viewDidLoad() function after creating the items array
But still I am not able to get the cells to appear in my view at all.
Can anyone suggest what am I missing here or what's wrong with my code, or how can I further debug this issue
import UIKit
import SideMenuSwift
class NavigationViewController: UIViewController {
#IBOutlet weak var navigationContainer: UIView!
#IBOutlet weak var emailButton: UIButton!
#IBOutlet weak var phoneButton: UIButton!
#IBOutlet weak var userAvatar: UIImageView!
#IBOutlet weak var userProfile: UIButton!
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var menuTable: UITableView!
var service: AuthenticationService!
var cdc: CoreDataController!
var items: [MenuItem] = []
var currentUser: User?
override func viewDidLoad() {
super.viewDidLoad()
setupSidebar()
initSidebarData()
setupUserHeader()
setupTableViews()
}
func setupUserHeader() {
if currentUser != nil {
if currentUser?.name != nil {
userName.text = currentUser?.name
} else if currentUser?.role != nil {
userName.text = "urTutors " + (currentUser?.role ?? "")
}
if currentUser?.avatarUrl != nil {
userAvatar.downloaded(from: (currentUser?.avatarUrl)!)
}
}
}
func initSidebarData() {
service = AuthenticationServiceProvider()
cdc = CoreDataController()
items = cdc.getNavigationData()
currentUser = cdc.getUserData()
}
func setupSidebar() {
self.view.backgroundColor = UIColor.hexColor("#fff")
navigationContainer.backgroundColor = UIColor.hexColor("#2a2a2a")
SideMenuController.preferences.basic.statusBarBehavior = .hideOnMenu
SideMenuController.preferences.basic.position = .above
SideMenuController.preferences.basic.direction = .left
SideMenuController.preferences.basic.enablePanGesture = true
SideMenuController.preferences.basic.menuWidth = 275
sideMenuController?.delegate = self
}
static func createViewController() -> NavigationViewController {
let sb = UIStoryboard(name: "StudentHomeModuleStoryboard", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "NavigationViewController")
return vc as! NavigationViewController
}
}
--UPDATE--
updated setupTableLayout function -
func setupTableViews() {
let bundle = Bundle(for: type(of: self))
let cellNib = UINib(nibName: "SideMenuTableItem", bundle: bundle)
menuTable.register(cellNib, forCellReuseIdentifier: "SideMenuTableItem")
menuTable.register(SideMenuTableItem.self, forCellReuseIdentifier: "SideMenuTableItem")
menuTable.reloadData()
}
After breaking into chat on this, we found that there were two issues.
The first issue was the missing reloadData call mentioned above. That was causing cellForRow to not be called. Adding reloadData corrected that issue, but then the custom cell class's outlets were nil, causing a crash in setItemData.
The second issue was that register(_:forCellReuseIdentifier:) was being called in code, but the custom cell was already setup as part of the Interface Builder UITableView declaration. Calling register again on the custom class re-registered the reuseIdentifier, disconnecting the outlets set up in the storyboard.
Removing the register call and adding reloadData solved all issues.
You are never calling setupTableViews(). You'r code should look like this:
class NavigationViewController: UIViewController, SideMenuControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setupTableViews()
}
func setupTableViews() {
menuTable.reloadData()
}
}
extension NavigationViewController: UITableViewDataSource, UITableViewDelegate {
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SideMenuTableItem", for: indexPath as IndexPath) as! SideMenuTableItem
cell.setItemData(items[indexPath.row])
return cell
}
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}
You are never calling the function, nor calling viewDidLoad. This should help. Also, where is the rest of your view controller code (is this all of it? It should not be!).
You don't need to register your cell because you requested it and make sure you reloadData().
Hope this helps!

Deleting a UITableView cell in a specific section

There is a task. Each cell contains a button by clicking which you want to delete this cell. The problem is that sections are used to delineate the entire list by category. The data I take from Realm DB. removal must occur under two conditions because the name is repeated, so you need to consider the name from the label and the name of the section. I will be very grateful for the sample code with comments.
import UIKit
import RealmSwift
class PurchesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var purchesTableView: UITableView!
let manage = ManagerData()
override func viewDidLoad() {
super.viewDidLoad()
purchesTableView.delegate = self
purchesTableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
purchesTableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return manage.loadPurchases().0.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return manage.loadPurchases().0[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return manage.loadPurchases().1[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "purchesCell", for: indexPath) as! CustomPurchesTableViewCell
cell.productLabel.text = manage.loadPurchases().1[indexPath.section][indexPath.row]
cell.weightProductLabel.text = manage.loadPurchases().2[indexPath.section][indexPath.row]
cell.weightNameLabel.text = manage.loadPurchases().3[indexPath.section][indexPath.row]
// cell.boughtButton.addTarget(self, action: #selector(removeProduct), for: .touchUpInside)
return cell
}
}
class CustomPurchesTableViewCell: UITableViewCell {
#IBOutlet weak var boughtButton: UIButton!
#IBOutlet weak var productLabel: UILabel!
#IBOutlet weak var weightProductLabel: UILabel!
#IBOutlet weak var weightNameLabel: UILabel!
#IBAction func removePurches(_ sender: Any) {
print("remove")
}
}
method for get data
func loadPurchases() -> ([String], Array<Array<String>>, Array<Array<String>>, Array<Array<String>>) {
var sections: [String] = []
var product = Array<Array<String>>()
var weight = Array<Array<String>>()
var nameWeight = Array<Array<String>>()
let realm = try! Realm()
let data = realm.objects(Purches.self)
for item in data {
if sections.contains(item.nameDish) == false {
sections.append(item.nameDish)
}
}
for a in sections {
var productArr = Array<String>()
var weightArr = Array<String>()
var nameWeightArr = Array<String>()
for prod in data {
if a == prod.nameDish {
productArr.append(prod.product)
weightArr.append(prod.weight)
nameWeightArr.append(prod.nameWeigh)
}
}
product.append(productArr)
weight.append(weightArr)
nameWeight.append(nameWeightArr)
}
return (sections, product, weight, nameWeight)
}
Index path you will get in cell class
Index path have two property section and row for table view
Now you can create on more method in Controller class and assign to a variable to every cell or you can use editAction provided by table view for delete
in order to get number section and row you need create IBOutlet in custom cell and on ViewController class is created addTarget for your button.
Example code at the bottom.
import UIKit
import RealmSwift
class PurchesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var purchesTableView: UITableView!
let manage = ManagerData()
//... more code ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "purchesCell", for: indexPath) as! CustomPurchesTableViewCell
cell.productLabel.text = manage.loadPurchases().1[indexPath.section][indexPath.row]
cell.weightProductLabel.text = manage.loadPurchases().2[indexPath.section][indexPath.row]
cell.weightNameLabel.text = manage.loadPurchases().3[indexPath.section][indexPath.row]
cell.boughtButton.addTarget(self, action: #selector(removePurches(_:)), for: .touchUpInside)
return cell
}
#objc func removePurches(_ sender: UIButton) {
let position: CGPoint = sender.convert(CGPoint.zero, to: purchesTableView)
let indexPath: IndexPath! = self.purchesTableView.indexPathForRow(at: position)
print("indexPath.row is = \(indexPath.row) && indexPath.section is = \(indexPath.section)")
purchesTableView.deleteRows(at: [indexPath], with: .fade)
}
}
and custom class CustomPurchesTableViewCell for cell
class CustomPurchesTableViewCell: UITableViewCell {
#IBOutlet weak var boughtButton: UIButton! // you button for press
#IBOutlet weak var productLabel: UILabel!
#IBOutlet weak var weightProductLabel: UILabel!
#IBOutlet weak var weightNameLabel: UILabel!
}

Separating UITableViewDelegate and UITableViewDataSource Causes No Data to Show

My ViewController is getting way too big because of all the methods needed for UITableViewDelegate and UITableViewDataSource, so I refactored my code to a different file, but now the data doesn't show up anymore...
Here's my current implementation:
In MyViewController.swift
class SomeView: UIViewController {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myDataSourceClass(tableView: myTableView)
}
}
In MyNewDataSourceClass.swift
class myDataSourceClass: UITableViewDelegate, UITableViewDataSource {
let stuff = [1, 2, 3]
init(tableView: UITableView) {
super.init()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")
cell?.textLabel?.text = "please show up"
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.stuff.count
}
}
Any help would be very appreciated. Thank you!
// you need to reload table after setting delegate and datasource
class SomeView: UIViewController {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myDataSourceClass(tableView: myTableView)
myTableView.reloadData()
}
}

Resources