I'm having trouble identifying why a tableViewCell keeps returning nil. This is the chunk of code I'm almost certain is causing the problem.
func tableView(tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath as IndexPath) as? CollectionViewCell
if cell == nil {
var nib = Bundle.main.loadNibNamed("CollectionCell", owner: self, options: nil)
cell = nib![0] as? CollectionViewCell
}
if cell == nil {
cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell") as! CollectionViewCell
}
// ...
}
This is the whole CollectionViewCell file as requested.
class CollectionViewCell: UITableViewCell {
#IBOutlet weak var txtNameCollection: UITextField!
#IBOutlet weak var btnGoToCollection: UIButton!
#IBOutlet weak var imgShelf: UIImageView!
#IBOutlet weak var btnNameCollection: UIButton!
#IBOutlet weak var btnEditCollectionName: UIButton!
#IBOutlet weak var imgNameCollection: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CollectionCell", bundle: nil), forCellReuseIdentifier: "CollectionCell")
}
func tableView(tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
//var cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath as IndexPath) as? CollectionViewCell
var cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell" ) as? CollectionViewCell
cell?.txtNameCollection.text = "Text"
return cell
You have to delete this because you use Xib File. And you dont do prototype cell on storyboard. There is no need. Just create a tableView with name is tableView
// if cell == nil {
// cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell") as! CollectionViewCell
// }
// if cell == nil {
// var nib = Bundle.main.loadNibNamed("CollectionCell", owner: self, options: nil)
// cell = nib![0] as? CollectionViewCell
// }
}
Related
I would really appreciate any help on this. I'm very new to coding, and have no luck implementing this feature so far. I'm looking to populate a UITableViewCell with information gathered from Firestore, namely: title, username and content. I've been able to print the 'title' array successfully, but have not been able to actually populate this into the cells.
This is the HomeViewController, where my UITableView is:
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var logoutButton: UIButton!
var postArray: [String] = []
var documents: [DocumentSnapshot] = []
let db = Firestore.firestore()
let currentUserID = Auth.auth().currentUser?.uid
// Find the UserIDs of people following
// Where Field for those UserIDs in "Posts"
override func viewDidLoad() {
super.viewDidLoad()
getFollowingPosts()
configureTableView()
}
func getFollowingPosts() {
let searchForFollowing = db.collection("users").document(currentUserID!).collection("Following")
searchForFollowing.getDocuments { (snapshot, error) in
for documents in snapshot!.documents {
let followedUID = documents.get("uid")
print(followedUID!)
self.db.collection("posts").whereField("uid", isEqualTo: followedUID!).getDocuments { (querySnapshot, error) in
for documents in querySnapshot!.documents {
let uid = documents.get("uid") as! String
let title = documents.get("Title") as! String
let ProfilePictureURL = documents.get("ProfilePictureURL") as! String
let username = documents.get("username") as! String
let content = documents.get("Content") as! String
self.postArray.append(title)
print(self.postArray)
}
self.tableView.reloadData()
}
}
}
}
func configureTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(PostTableViewCell.self, forCellReuseIdentifier: "PostCell")
// remove separators for empty cells
tableView.tableFooterView = UIView()
// remove separators from cells
tableView.separatorStyle = .none
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
postArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostTableViewCell
let post = postArray[indexPath.row]
return cell
}
}
This is my PostTableViewCell:
class PostTableViewCell: UITableViewCell {
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var contentLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
addSubview(usernameLabel)
addSubview(titleLabel)
addSubview(contentLabel)
}
}
If anyone could help, this would be massively appreciated. Like I said, I've been struggling a lot with this one.
You don't seem to be setting the data onto anything in the cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostTableViewCell
let post = postArray[indexPath.row]
cell.titleLabel.text = post
return cell
}
Also, modify the register method if you're using nib
func configureTableView() {
//...
tableView.register(UINib(nibName: "PostCell", bundle: nil), forCellReuseIdentifier: "PostCell")
//...
}
Note: Make sure that the nib file has nib's identifier set as "PostCell".
Im trying to implement BEMCheckBox and the myCheckBox.delegate = self needs to be se in viewDidLoad.
How do I do this in a tableView?
I have done this to my cells and tableView:
Cell file for the tableView:
import UIKit
import BEMCheckBox
protocol SizeSelectionDelegate: NSObjectProtocol {
func didChooseSmall(cell: SizeSelectorCell)
func didChooseLarge(cell: SizeSelectorCell)
}
class SizeSelectorCell: UITableViewCell {
#IBOutlet weak var smallSizeCheckBox: BEMCheckBox!
#IBOutlet weak var largeSizeCheckBox: BEMCheckBox!
#IBOutlet weak var smallSizePriceLabel: UILabel!
#IBOutlet weak var largeSizePriceLabel: UILabel!
weak var delegate: SizeSelectionDelegate?
func didTap(_ checkBox: BEMCheckBox) {
if checkBox.tag == 0 {
delegate?.didChooseSmall(cell: self)
}
if checkBox.tag == 1 {
delegate?.didChooseLarge(cell:self)
}
}
}
TableViewController:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "InfoCell") as! InfoTableViewCell
cell.nameLabel.text = name
cell.detailLabel.text = detail
cell.smallPriceLabel.text = String (smallPrice)
cell.largePriceLabel.text = String (largePrice)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "SizeSelector") as! SizeSelectorCell
cell.smallSizePriceLabel.text = String (smallPrice)
cell.largeSizePriceLabel.text = String (largePrice)
return cell
}
}
extension InfoTableViewController: SizeSelectionDelegate
{
func didChooseSmall(cell: SizeSelectorCell) {
size = "Small"
print(size)
}
func didChooseLarge(cell: SizeSelectorCell) {
size = "Large"
print(size)
}
}
You need to set the delegate cell.delegate = self inside cellForRowAt
let cell = tableView.dequeueReusableCell(withIdentifier: "SizeSelector") as! SizeSelectorCell
cell.delegate = self
cell.smallSizePriceLabel.text = String (smallPrice)
cell.largeSizePriceLabel.text = String (largePrice)
return cell
I'm working on a swift assignment about table view controller and my table view doesn't have anything on it. I have correctly connected the labels and classes and assigned tableview cell identifier as "cell" in the attribute on storyboard but I still have the error "need to register nib" and even if I wrote self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "Cell") the error is gone but there's still nothing on it.
My cell class is as below.
class cartTableViewCell: UITableViewCell {
#IBOutlet weak var itemImage: UIImageView!
#IBOutlet weak var itemName: UILabel!
#IBOutlet weak var itemQuan: UILabel!
#IBOutlet weak var itemFrame: UILabel!
#IBOutlet weak var itemSize: UILabel!
#IBOutlet weak var itemPrice: UILabel!
#IBOutlet weak var itemSub: UILabel!
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}`
my function is
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier:"Cell", for: indexPath) as! cartTableViewCell
let item = itemArray[indexPath.row]
cell.itemName?.text = item.itemName!
cell.itemFrame?.text = "haha"//itemArray[indexPath.row].itemFrame!
cell.itemSize?.text = item.itemSize!
cell.itemPrice?.text = item.sellingPrice!
//cell.itemQuan?.text =
cell.itemSub?.text = "\(Int(item.sellingNumber!)! * Int(item.sellingPrice!)!)"
return cell
}`
If I print(item.itemName), I can get some value. cell.itemName?.text is nil
I checked some answers online but so far no luck. Any help is highly appreciated.
Remove code
self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "Cell")
Write below code in cartTableViewCell
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// code common to all your cells goes here
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Now modify your code with below code
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier:"Cell", for: indexPath) as! cartTableViewCell
if cell == nil {
cell = cartTableViewCell.init(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
let item = itemArray[indexPath.row]
cell.itemName?.text = item.itemName!
cell.itemFrame?.text = "haha"//itemArray[indexPath.row].itemFrame!
cell.itemSize?.text = item.itemSize!
cell.itemPrice?.text = item.sellingPrice!
//cell.itemQuan?.text =
cell.itemSub?.text = "\(Int(item.sellingNumber!)! * Int(item.sellingPrice!)!)"
return cell
}
Just check the reuse identifier name in your code. I am just writing this for more explanation.
viewDidLoad(){
let customNib = UINib(nibName: "CustomCell", bundle: Bundle.main)
tableView.register(customNib, forCellReuseIdentifier: "customCell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomCell
cell.configureCell(text: data[indexPath.row])
}
Never do this :
let cell = self.tableView.dequeueReusableCell(withIdentifier:"Cell", for: indexPath) as! cartTableViewCell
if cell == nil {
cell = cartTableViewCell.init(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
Explantion :
A UITableViewCell object with the associated reuse identifier. This
method always returns a valid cell. Ref:https://developer.apple.com/documentation/uikit/uitableview/1614878-dequeuereusablecell.
Do this, I just got this error today and I got it fixed by :
let yourNib = UINib(nibName: "yourNibName", bundle: Bundle.main)
yourTableView.register(yourNib, forCellReuseIdentifier: "cell")
The problem is that when I am selecting some value (in the field picker -SwiftyPickerPopover-) in a row, the action updates the same value (selected in picker) for all rows.
The code that I am using for this for the ViewController (with UITableView inside):
func btnExpenseTypePressed(at index: IndexPath) {
var tiposGasto: [String] = [String]()
for gasto in dataManager.expensesType {
tiposGasto.append(gasto.tipoGasto!)
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: index) as! ExpenseDetailCell
StringPickerPopover.appearFrom(
originView: cell.btnExpenseType,
baseViewController: self,
title: "Tipos de Gasto",
choices: tiposGasto,
initialRow:0,
doneAction: { selectedRow, selectedString in
print("Seleccion \(selectedString)")
//self.valueSelected = selectedString
cell.btnExpenseType.setTitle(selectedString, for: .normal)
self.tableView.reloadData()
} ,cancelAction: { print("cancel")}
)
}
func btnCostCenterPressed(at index: IndexPath) {
var centroCoste: [String] = [String]()
for centro in dataManager.costsCenter {
centroCoste.append(centro.centroCoste!)
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: index) as! ExpenseDetailCell
StringPickerPopover.appearFrom(
originView: cell.btnCostCenter,
baseViewController: self,
title: "Centro de Coste",
choices: centroCoste,
initialRow:0,
doneAction: { selectedRow, selectedString in
print("Seleccion \(selectedString)")
//self.valueSelected = selectedString
cell.btnCostCenter.setTitle(selectedString, for: .normal)
self.tableView.reloadData()
} ,cancelAction: { print("cancel")}
)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell? = UITableViewCell()
if tableView == self.tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! ExpenseDetailCell
cell.selectionStyle = .none
cell.delegate = self
debugPrint("First table load \(firstTableLoad)")
if firstTableLoad {
cell.btnCostCenter.setTitle(dataManager.costsCenter[0].centroCoste, for: .normal)
cell.btnExpenseType.setTitle(dataManager.expensesType[0].tipoGasto, for: .normal)
firstTableLoad = false
}
return cell
}
if tableView == self.tableViewImages {
let cell = tableView.dequeueReusableCell(withIdentifier: "imagesCellIdentifier", for: indexPath) as! ExpenseImageCell
cell.imageView?.image = UIImage(named: "imgPlaceholder")
cell.selectionStyle = .none
return cell
}
return cell!
}
The btnExpenseTypePressed and btnCostCenterPressed methods are delegate from the ExpenseDetailCell:
protocol ExpenseDetailDelegate {
func switchChanged(at index: IndexPath)
func amountEditedChanged(at index: IndexPath)
func btnExpenseTypePressed(at index: IndexPath)
func btnCostCenterPressed(at index: IndexPath)
}
class ExpenseDetailCell: UITableViewCell {
var delegate: ExpenseDetailDelegate!
var indexPath: IndexPath!
var dataManager = DataManager.sharedInstance
#IBOutlet weak var txtAmountNumber: UITextField!
#IBOutlet weak var txtId: UITextField!
#IBOutlet weak var txtAmountPercent: UITextField!
#IBOutlet weak var lblTotal: UILabel!
#IBOutlet weak var lblSeparator: UILabel!
#IBOutlet weak var lblPercent: UILabel!
#IBOutlet weak var btnExpenseType: UIButton!
#IBOutlet weak var btnCostCenter: UIButton!
#IBOutlet weak var switchID: UISwitch!
#IBAction func btnExpenseTypePressed(_ sender: Any) {
debugPrint("En btnExpenseTypePressed")
self.delegate?.btnExpenseTypePressed(at: indexPath)
debugPrint("El INDEX \(indexPath)")
}
#IBAction func btnCostCenterPressed(_ sender: Any) {
debugPrint("En btnCostCenterPressed")
self.delegate?.btnCostCenterPressed(at: indexPath)
debugPrint("El INDEX \(indexPath)")
}
#IBAction func amountEditedChanged(_ sender: Any) {
debugPrint("En amountEditedChanged")
self.delegate?.amountEditedChanged(at: indexPath)
lblTotal.text = txtAmountNumber.text
}
#IBAction func switchChanged(_ sender: Any) {
debugPrint("En value changed")
self.delegate?.switchChanged(at: indexPath)
if switchID.isOn {
debugPrint("Dentro if")
txtId.text = ""
txtId.isEnabled = false
} else {
txtId.isEnabled = true
}
}
}
I am using SWIFT 3.
I believe the error comes from a missunderstanding of what you want to do and what you are acctually doing.
You want: Change one value in one cell
You do: Change one value in all cells ON cell creation.
When you call: self.tableView.reloadData() in unc btnExpenseTypePressed(at index: IndexPath) iOS calls
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) again and again skipping the `firstTableLoad = false` and loading all the tableviewCells with the same value.
You have also set the index to 0 in DataManager.costsCenter[0] which will mean that all the cells on creation will have the same value.
My suggestion: Do your changes in:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
}
If by any chance this doesn't help you check clean the cell in :
override func prepareForReuse()
{
super.prepareForReuse()
}
or just set it like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell? = UITableViewCell()
if tableView == self.tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! ExpenseDetailCell
cell.selectionStyle = .none
cell.delegate = self
cell.setMyCustomText("")...
}
return cell
}
I've been trying to use the custom cell in function when button is clicked. and update a label in that specific row using the function.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CardCell
cell.startcount.tag = indexPath.row
cell.startcount.addTarget(self, action: "startcount:", forControlEvents:UIControlEvents.TouchUpInside)
}
here is the function I'm using
func startcount(sender: AnyObject){
// create a reference of CardCell
// update the counter like cell.textcount.text = "\(counter)"
// in the specific row
}
My custom cell class :
import UIKit
class CardCell: UITableViewCell {
#IBOutlet weak var textcount: UILabel!
#IBOutlet weak var startcount: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
func startcount(sender: AnyObject){
let button = sender as UIButton
let indexPath = NSIndexPath(forRow:button.tag inSection:0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as CardCell
// update cell
}
For Swift 4 and above
func startCount(sender : AnyObject) {
let button = sender as! UIButton
let indexPath = IndexPath(row:button.tag ,section:0)
let cell = tableView.cellForRow(at: indexPath) as! CardCell
// update cell
}