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".
I want to reuse a UITableViewCell in my app, but I get this error: Unexpectedly found nil while implicitly unwrapping an Optional value.
I find that this is because the UI things in UITableViewCell is nil, so my app crashed.
My UITableViewCell code is like this:
class WordListCell: UITableViewCell {
#IBOutlet weak var wordListCoverImage: UIImageView!
#IBOutlet weak var wordListName: UILabel!
#IBOutlet weak var wordListInfo: UILabel!
var wordList: WordList? {
didSet {
updateUI()
}
}
private func updateUI() {
wordListName.text = wordList?.name
wordListInfo.text = wordList?.description
wordListCoverImage = UIImage()
}
}
I create it in the storyboard and link the outlet to the code in the other TableView.
But this time, I want to reuse the cell in a new TableView which is all created by code, so I don't know how to initialize the UI things.
The new UITableView code is like this:
tableView.delegate = self
tableView.dataSource = self
tableView.register(WordListCell.self, forCellReuseIdentifier: "wordListCell")
//the delegate
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return wordLists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let wordList = wordLists[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "wordListCell", for: indexPath)
if let wordListCell = cell as? WordListCell {
wordListCell.wordList = wordList
}
return cell
}
Please tell me how to reuse the cell.Thanks!
Okay so I think what you are doing wrong is when you create a custom tableView cell, you are not assigning a UIImage. So instead try doing this wordListCoverImage = UIImage(named: wordList.imageName).
Now also in your tableView class inside viewDidLoad() apart from adding
tableView.delegate = self
tableView.dataSource = self
tableView.register(WordListCell.self, forCellReuseIdentifier: "wordListCell")
Then at let cell = tableView.dequeueReusableCell(withIdentifier: "wordListCell", for: indexPath) downcast it as a custom cell class like so.
let cell = tableView.dequeueReusableCell(withIdentifier: "wordListCell", for: indexPath) as! WordListCell
And then finaly under that set the cell.delegate = self
I hope this helps!
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
// }
}
I am trying to update the cells on a table view but the cell is not reading the text I am passing and returning nil.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! MyCell
let item = self.items[indexPath.row]
myCell.nameLabel?.text = item as? String
print( self.items[indexPath.row])
myCell.myTableViewController = self
return myCell
}
class MyCell: UITableViewCell {
var myTableViewController: ChangeFeedViewController!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#IBOutlet weak var nameLabel: UILabel! = {
let label = UILabel()
label.text = "Any Label"
return label
}()
#IBOutlet weak var actionButton: UIButton! = {
let button = UIButton()
button.setTitle("Action", for: .normal)
return button
}()
#IBAction func buttonHandleAction(_ sender: Any) {
handelAction()
}
func handelAction(){
myTableViewController.deleteCell(cell: self)
}
}
You need to modify your outlet like this and connect to your interface builder of MyCell class.
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var actionButton: UIButton!
I'm trying to create a custom table view cell from a nib. I'm referring to this article here. I'm facing two issues.
I created a .xib file with a UITableViewCell object dragged on to it. I created a subclass of UITableViewCell and set it as the cell's class and Cell as the reusable identifier.
import UIKit
class CustomOneCell: UITableViewCell {
#IBOutlet weak var middleLabel: UILabel!
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: UILabel!
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
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
}
}
In the UITableViewController I have this code,
import UIKit
class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
var items = ["Item 1", "Item2", "Item3", "Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - UITableViewDataSource
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let identifier = "Cell"
var cell: CustomOneCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
if cell == nil {
tableView.registerNib(UINib(nibName: "CustomCellOne", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
}
return cell
}
}
This code complies with no errors but when I run it in the simulator, it looks like this.
In the UITableViewController in the storyboard I haven't done anything to the cell. Blank identifier and no subclass. I tried adding the Cell identifier to the prototype cell and ran it again but I get the same result.
Another error I faced is, when I tried to implement the following method in the UITableViewController.
override func tableView(tableView: UITableView!, willDisplayCell cell: CustomOneCell!, forRowAtIndexPath indexPath: NSIndexPath!) {
cell.middleLabel.text = items[indexPath.row]
cell.leftLabel.text = items[indexPath.row]
cell.rightLabel.text = items[indexPath.row]
}
As shown in the article I mentioned I changed the cell parameter's type form UITableViewCell to CustomOneCell which is my subclass of UITableViewCell. But I get the following error,
Overriding method with selector 'tableView:willDisplayCell:forRowAtIndexPath:' has incompatible type '(UITableView!, CustomOneCell!, NSIndexPath!) -> ()'
Anyone have any idea how to resolve these errors? These seemed to work fine in Objective-C.
Thank you.
EDIT: I just noticed if I change the simulator's orientation to landscape and turn it back to portrait, the cells appear! I still couldn't figure out what's going on. I uploaded an Xcode project here demonstrating the problem if you have time for a quick look.
With Swift 5 and iOS 12.2, you should try the following code in order to solve your problem:
CustomCell.swift
import UIKit
class CustomCell: UITableViewCell {
// Link those IBOutlets with the UILabels in your .XIB file
#IBOutlet weak var middleLabel: UILabel!
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: UILabel!
}
TableViewController.swift
import UIKit
class TableViewController: UITableViewController {
let items = ["Item 1", "Item2", "Item3", "Item4"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
}
// MARK: - UITableViewDataSource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.middleLabel.text = items[indexPath.row]
cell.leftLabel.text = items[indexPath.row]
cell.rightLabel.text = items[indexPath.row]
return cell
}
}
The image below shows a set of constraints that work with the provided code without any constraints ambiguity message from Xcode:
Here's my approach using Swift 2 and Xcode 7.3. This example will use a single ViewController to load two .xib files -- one for a UITableView and one for the UITableCellView.
For this example you can drop a UITableView right into an empty TableNib.xib file. Inside, set the file's owner to your ViewController class and use an outlet to reference the tableView.
and
Now, in your view controller, you can delegate the tableView as you normally would, like so
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
...
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Table view delegate
self.tableView.delegate = self
self.tableView.dataSource = self
...
To create your Custom cell, again, drop a Table View Cell object into an empty TableCellNib.xib file. This time, in the cell .xib file you don't have to specify an "owner" but you do need to specify a Custom Class and an identifier like "TableCellId"
Create your subclass with whatever outlets you need like so
class TableCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
}
Finally... back in your View Controller, you can load and display the entire thing like so
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// First load table nib
let bundle = NSBundle(forClass: self.dynamicType)
let tableNib = UINib(nibName: "TableNib", bundle: bundle)
let tableNibView = tableNib.instantiateWithOwner(self, options: nil)[0] as! UIView
// Then delegate the TableView
self.tableView.delegate = self
self.tableView.dataSource = self
// Set resizable table bounds
self.tableView.frame = self.view.bounds
self.tableView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
// Register table cell class from nib
let cellNib = UINib(nibName: "TableCellNib", bundle: bundle)
self.tableView.registerNib(cellNib, forCellReuseIdentifier: self.tableCellId)
// Display table with custom cells
self.view.addSubview(tableNibView)
}
The code shows how you can simply load and display a nib file (the table), and second how to register a nib for cell use.
Hope this helps!!!
Swift 4
Register Nib
override func viewDidLoad() {
super.viewDidLoad()
tblMissions.register(UINib(nibName: "MissionCell", bundle: nil), forCellReuseIdentifier: "MissionCell")
}
In TableView DataSource
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MissionCell", for: indexPath) as? MissionCell else { return UITableViewCell() }
return cell
}
Detailed Solution with Screenshots
Create an empty user interface file and name it MyCustomCell.xib.
Add a UITableViewCell as the root of your xib file and any other visual components you want.
Create a cocoa touch class file with class name MyCustomCell as a subclass of UITableViewCell.
Set the custom class and reuse identifier for your custom table view cell.
Open the assistant editor and ctrl+drag to create outlets for your visual components.
Configure a UIViewController to use your custom cell.
class MyViewController: UIViewController {
#IBOutlet weak var myTable: UITableView!
override func viewDidLoad {
super.viewDidLoad()
let nib = UINib(nibName: "MyCustomCell", bundle: nil)
myTable.register(nib, forCellReuseIdentifier: "MyCustomCell")
myTable.dataSource = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomCell") as? MyCustomCell {
cell.myLabel.text = "Hello world."
return cell
}
...
}
}
swift 4.1.2
xib.
Create ImageCell2.swift
Step 1
import UIKit
class ImageCell2: UITableViewCell {
#IBOutlet weak var imgBookLogo: UIImageView!
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var lblPublisher: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
step 2 . According Viewcontroller class
import UIKit
class ImageListVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tblMainVC: UITableView!
var arrBook : [BookItem] = [BookItem]()
override func viewDidLoad() {
super.viewDidLoad()
//Regester Cell
self.tblMainVC.register(UINib.init(nibName: "ImageCell2", bundle: nil), forCellReuseIdentifier: "ImageCell2")
// Response Call adn Disply Record
APIManagerData._APIManagerInstance.getAPIBook { (itemInstance) in
self.arrBook = itemInstance.arrItem!
self.tblMainVC.reloadData()
}
}
//MARK: DataSource & delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrBook.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// [enter image description here][2]
let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell2") as! ImageCell2
cell.lblTitle.text = self.arrBook[indexPath.row].title
cell.lblPublisher.text = self.arrBook[indexPath.row].publisher
if let authors = self.arrBook[indexPath.row].author {
for item in authors{
print(" item \(item)")
}
}
let url = self.arrBook[indexPath.row].imageURL
if url == nil {
cell.imgBookLogo.kf.setImage(with: URL.init(string: ""), placeholder: UIImage.init(named: "download.jpeg"))
}
else{
cell.imgBookLogo.kf.setImage(with: URL(string: url!)!, placeholder: UIImage.init(named: "download.jpeg"))
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
}
You did not register your nib as below:
tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
Another method that may work for you (it's how I do it) is registering a class.
Assume you create a custom tableView like the following:
class UICustomTableViewCell: UITableViewCell {...}
You can then register this cell in whatever UITableViewController you will be displaying it in with "registerClass":
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UICustomTableViewCell.self, forCellReuseIdentifier: "UICustomTableViewCellIdentifier")
}
And you can call it as you would expect in the cell for row method:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UICustomTableViewCellIdentifier", forIndexPath: indexPath) as! UICustomTableViewCell
return cell
}
For fix the "Overriding method... has incompatible type..." error I've changed the function declaration to
override func tableView(tableView: (UITableView!),
cellForRowAtIndexPath indexPath: (NSIndexPath!))
-> UITableViewCell {...}
(was -> UITableViewCell! -- with exclamation mark at the end)
I had to make sure that when creating the outlet to specify that I was hooking to the cell, not the object's owner. When the menu appears to name it you have to select it in the 'object' dropdown menu. Of course you must declare the cell as your class too, not just 'TableViewCellClass'. Otherwise I would keep getting the class not key compliant.
Simple take a xib with class UITableViewCell. Set the UI as per reuirement and assign IBOutlet. Use it in cellForRowAt() of table view like this:
//MARK: - table method
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrayFruit.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:simpleTableViewCell? = tableView.dequeueReusableCell(withIdentifier:"simpleTableViewCell") as? simpleTableViewCell
if cell == nil{
tableView.register(UINib.init(nibName: "simpleTableViewCell", bundle: nil), forCellReuseIdentifier: "simpleTableViewCell")
let arrNib:Array = Bundle.main.loadNibNamed("simpleTableViewCell",owner: self, options: nil)!
cell = arrNib.first as? simpleTableViewCell
}
cell?.labelName.text = self.arrayFruit[indexPath.row]
cell?.imageViewFruit.image = UIImage (named: "fruit_img")
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 100.0
}
100% working without any issue (Tested)
This line add in TableView cell:
static var nib : UINib{
return UINib(nibName: identifier, bundle: nil)
}
static var identifier : String{
return String(describing: self)
}
And register in viewcontroller like
This line use in viewDidLoad
tableview.register(TopDealLikedTableViewCell.nib, forCellReuseIdentifier: TopDealLikedTableViewCell.identifier)
cell for row at indexpath
if let cell = tableView.dequeueReusableCell(withIdentifier:
TopDealLikedTableViewCell.identifier) as? TopDealLikedTableViewCell{
return cell
}
return UITableViewCell()
Set on cell
static var identifier : String {
return String(describing: self)
}
static var nib : UINib {
return UINib(nibName: identifier, bundle: nil)
}