TableViewCell.xib doesn't appear on tableview - swift

Here is my code, it is supposed to display the users inside firebase database in customs tableviewcell.xib but when launching the app the tableview stays empty, I really don't know what's wrong in the code or what's missing, I think it is a really simple mistake but I can't figure it out.
Thanks in advance for those who will answer.
import UIKit
import Firebase
class UsersTableView: UIViewController, UITableViewDelegate, UITableViewDataSource {
// Outlets.
#IBOutlet weak var tableview: UITableView!
// Var.
var user = [User]()
override func viewDidLoad() {
super.viewDidLoad()
retrieveUsers()
// Do any additional setup after loading the view.
}
func retrieveUsers() {
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { DataSnapshot in
let users = DataSnapshot.value as! [String: AnyObject]
self.user.removeAll()
for (_, value) in users{
//let uid = Auth.auth().currentUser!.uid
if let uid = value["userID"] as? String{
if uid != Auth.auth().currentUser!.uid {
let userToShow = User()
if let fullName = value["username"] as? String , let imagePath = value["photoURL"] as? String {
userToShow.username = fullName
userToShow.imagePath = imagePath
userToShow.userID = uid
self.user.append(userToShow)
}
}
}
}
self.tableview.reloadData()
})
ref.removeAllObservers()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableview.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) as! UserTableViewCell
cell.nameLabel.text = self.user[indexPath.row].username
cell.userID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
//checkFollowing(indexPath: indexPath)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return user.count ?? 0
}
}
extension UIImageView{
func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil{
print(error)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}
}

If you have not set delegate and datasource for your tableView in your storyboard do it programmatically:
override func viewDidLoad() {
super.viewDidLoad()
//Add these 2 lines, might be missed.
self.tableview.delegate = self
self.tableview.dataSource = self
retrieveUsers()
}

CheckList:
Set tableView Delegate and Datasource
self.tableview.delegate = self
self.tableview.dataSource = self
Registered custom tableViewCell?
let cellNIb = UINib.init(nibName:"Identifier_Name", bundle: nil)
register(cellNIb, forCellReuseIdentifier: identifier)
check the return count of func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
​

There are two things that you forgot:
Set dataSource of your table view as your controller. If you don't do it, your tableView won't want any data. So set it in controller's viewDidLoad
tableview.dataSource = self
If you created custom xib for your cell, don't forget to register your custom cell for table view (also you can do it in viewDidLoad)
tableview.register(UINib(nibName: "UserCardTableViewCell", bundle: nil), forCellReuseIdentifier: "UserCell")
If you need UITableViewDelegate methods like didSelectRowAt too, don't forget to set delegate of your table view as your controller too
tableview.delegate = self

Related

Table View is now shown in simülatör swift/xcode

hello i am new to learning swift. I want to save data in database and show it in tableview. But even though I do everything, the tableview does not appear in the simulator. white screen appears. Any idea about the reason? I looked at the previous questions but couldn't find an answer.
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
//tanımlamalar
var nameArray = [String]()
var idArray = [UUID]()
override func viewDidLoad() {
super.viewDidLoad()
//tableview gösterme
tableView.delegate = self
tableView.dataSource = self
//add butonu ekleme
navigationController?.navigationBar.topItem?.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.add, target: self, action: #selector(addButtonClicked))
}
//verileri getirme
func getData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
//getirme
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName : "Paintings")
fetchRequest.returnsObjectsAsFaults = false
do{
let results = try context.fetch(fetchRequest)
for result in results as! [NSManagedObject] {
if let name = result.value(forKey: "name") as? String{
self.nameArray.append(name)
}
if let id = result.value(forKey: "id") as? UUID{
self.idArray.append(id)
}
//yeni veri eklenirse tableviewı reload et
self.tableView.reloadData()
}
}catch{
print("error")
}
}
//add butonuna tıklanırsa ne olacak
#objc func addButtonClicked() {
performSegue(withIdentifier: "DetailsVC", sender: nil)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nameArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
var content = cell.defaultContentConfiguration()
content.text = nameArray[indexPath.row]
cell.contentConfiguration = content
return cell
}
}

why is storyboard UITableView not showing

I am a novice to swift. This is my first assignment for UI development. I have done the exercise perfectly and the tableView showed up as expected. The code is as below:
import UIKit
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate{
}
extension ViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "gameScoreCell", for: indexPath)
cell.textLabel?.text = "hello world"
cell.detailTextLabel?.text = "score"
return cell
}
}
However, when I followed the same step and tried to integrate it with my project (with a navigation controller), the table view does not show up. Did I miss anything?
import UIKit
class HightScoreVC: UIViewController {
#IBOutlet var rankingTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
rankingTable.delegate = self
rankingTable.dataSource = self
}
}
extension HightScoreVC: UITableViewDelegate{
}
extension HightScoreVC: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "gameScoreCell", for: indexPath)
cell.textLabel?.text = "hello world"
cell.detailTextLabel?.text = "123"
return cell
}
}
I think you must register your cell in ViewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
rankingTable.delegate = self
rankingTable.dataSource = self
rankingTable.register(UITableViewCell.self, forCellReuseIdentifier: "gameScoreCell")
}
Points to keep in mind while working with tableview in swift.
Make sure constriants of tableview are given properly.
You have connected the class to the view controller in the identity inspector.
Provide delegate and datasource in viewDidLoad() itself rather than storyboard for better practice.
If you are creating xib for a cell, make sure you have registered the cell for your tableview, or if you are providing prototype cell, make sure you provide dequeueReusableCell() method and initialize your cell for some specific class.
Simple example for a tableview with some prototype cell
import UIKit
class UsersListViewController: UIViewController, Storyboarded {
//MARK: - Variables
var coordinator: AuthenticationCoordinator?
var usersList: UsersList?
//MARK: - Outlets
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var progressBar: UIActivityIndicatorView!
#IBOutlet weak var btnAddUser: UIButton!
//MARK: - UIViewController
override func viewDidLoad() {
super.viewDidLoad()
initializeView()
getUsersList()
}
//MARK: - Actions
#IBAction func addUserAction(_ sender: UIButton) {
coordinator?.presentAddUser()
}
//MARK: - File private functions
fileprivate func initializeView() {
self.title = "Users list"
progressBar.startAnimating()
btnAddUser.layer.masksToBounds = true
btnAddUser.layer.cornerRadius = btnAddUser.frame.height / 2
tableView.delegate = self
tableView.dataSource = self
}
fileprivate func getUsersList() {
guard let url = URL(string: ApiUrl.delayResponseURL.rawValue) else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else { return }
guard let data = data else { return }
guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else { return }
do {
guard let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { return }
guard let prettyJsonData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) else { return }
guard let responseData = try? JSONDecoder().decode(UsersList.self, from: prettyJsonData) else { return }
self.usersList = responseData
DispatchQueue.main.async {
self.progressBar.stopAnimating()
self.progressBar.alpha = 0
self.tableView.reloadData()
}
} catch {
return
}
}.resume()
}
}//End of class
//MARK: - UITableViewDelegate
extension UsersListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let index = usersList?.data[indexPath.row].userID {
coordinator?.startSingleUserVC(index)
tableView.deselectRow(at: indexPath, animated: true)
}
}
}//End of extension
//MARK: - UITableViewDataSource
extension UsersListViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "singleUserCell") as? SingleUserTableViewCell {
if let url = URL(string: usersList?.data[indexPath.row].avatar ?? "") {
DispatchQueue.global().async {
guard let data = try? Data(contentsOf: url) else { return }
val currentUser = self.usersList?.data[indexPath.row]
DispatchQueue.main.async {
cell.initCell(data, currentUser.firstName, currentUser.email)
}
}
}
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usersList?.data.count ?? 1
}
}//End of extension

Displaying Firebase data in a tableview

I am trying to retrieve information stored in a Firebase Database, but my tableview is not displaying the information. I have tried using print functions to see if the data is being retrieved, and it shows that this is the case, but the tableview shows up as blank when I run the simulator.
I am using Xcode 11 and every tutorial that I have looked at is not working for some reason.
Here is my code:
import UIKit
import Firebase
import FirebaseDatabase
import SwiftKeychainWrapper
import FirebaseAuth
class FeedVC: UITableViewController {
var currentUserImageUrl: String!
var posts = [postStruct]()
var selectedPost: Post!
override func viewDidLoad() {
super.viewDidLoad()
getUsersData()
getPosts()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getUsersData(){
guard let userID = Auth.auth().currentUser?.uid else { return }
Database.database().reference().child("users").child(userID).observeSingleEvent(of: .value) { (snapshot) in
if let postDict = snapshot.value as? [String : AnyObject] {
self.tableView.reloadData()
}
}
}
struct postStruct {
let firstName : String!
let lastName : String!
}
func getPosts() {
let databaseRef = Database.database().reference()
databaseRef.child("profiles").queryOrderedByKey().observeSingleEvent(of: .childAdded, with: {
snapshot in
let firstName = (snapshot.value as? NSDictionary)!["profileForename"] as? String
let lastName = (snapshot.value as? NSDictionary
)!["profileSurname"] as? String
print(firstName)
self.posts.append(postStruct(firstName: firstName, lastName: lastName))
print(self.posts)
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell else { return UITableViewCell() }
let nameLabel = cell.viewWithTag(1) as! UILabel
nameLabel.text = posts[indexPath.row].firstName
return cell
}
}
Any help would be much appreciated!
Update: Since PostCell is created in the storyboard within the table view it's registered and dequeued successfully. So the issue is being narrowed down to the label with tag 1. Try creating an #IBOutlet for the label and use that to set the text of UILabel.
Then in cellForRowAt:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell else { return UITableViewCell() }
cell.firstNameLabel.text = posts[indexPath.row].firstName
return cell
}
Previous: You seem to have forgotten to register the PostCell.
override func viewDidLoad() {
super.viewDidLoad()
//...
tableView.register(PostCell.self, forCellReuseIdentifier: "PostCell")
}
Note: If you've created PostCell in Xib use nib registry method.
Update: If you want to register with Nib method use:
tableView.register(UINib(nibName: <#T##String#>, bundle: nil), forCellReuseIdentifier: "PostCell") // provide the xib file name at the placeholder

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'pizzaSegue'

I am new to swift programming and running into errors with performing a segue from a tableview cell when it is pressed to a view controller giving details about that cell. The error I am getting is:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'Receiver (<DrinkupClient.DrinkListTableViewController: 0x7fec5d431510>)
has no segue with identifier 'pizzaSegue''
I have already tried the following:
1) Tried renaming the storyboard and make sure to set the main storyboard in the project settings and in the info.plist file (Key is 'Main storyboard file base name'). I currently have the storyboard named: "Main.storyboard"
2) Tried doing a clean of the product (Product -> Clean) and rebuild but this gives same error
3) I have tried deleting the app from the simulator and running it again
4) I have double checked and the segue identifier in interface builder is called "pizzaSegue" and it is the same in my code.
import UIKit
import Alamofire
struct Drink {
let id: String
let name: String
let description: String
let amount: Float
let image: UIImage
init(data: [String: Any]) {
self.id = data["id"] as! String
self.name = data["name"] as! String
//self.amount = data["amount"] as! Float
self.amount = ((data["amount"] as? NSNumber)?.floatValue)!
self.description = data["description"] as! String
self.image = data["image"] as! UIImage
}
}
class DrinkTableViewCell: UITableViewCell {
#IBOutlet weak var cellName: UILabel!
#IBOutlet weak var cellAmount: UILabel!
#IBOutlet weak var cellDescription: UILabel!
#IBOutlet weak var cellImage: UIImageView!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class DrinkListTableViewController: UITableViewController {
var drinks: [Drink] = []
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Drink Selection"
tableView.dataSource = self
tableView.delegate = self
//tableView.register(DrinkTableViewCell.self, forCellReuseIdentifier: "cell")
tableView.register(DrinkTableViewCell.self as AnyClass, forCellReuseIdentifier: "cell")
//tableView.register(UINib(nibName: "DrinkTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")
//tableView.estimatedRowHeight = 134
//tableView.rowHeight = UITableView.automaticDimension
fetchInventory { drinks in
guard drinks != nil else { return }
self.drinks = drinks!
//print("Data from API call: ", self.drinks)
//self.tableView.reloadData()
// DispatchQueue.main.async { [weak self] in
// self?.tableView.reloadData()
// }
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "pizzaSegue", sender: self.drinks[indexPath.row] as Drink)
//trying another method below?
//self.navigationController?.pushViewController(UIViewController() as! PizzaViewController, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pizzaSegue" {
guard let vc = segue.destination as? PizzaViewController else { return }
vc.pizza = sender as? Pizza
}
}
private func fetchInventory(completion: #escaping ([Drink]?) -> Void) {
Alamofire.request("http://127.0.0.1:4000/inventory", method: .get)
.validate()
.responseJSON { response in
guard response.result.isSuccess else { return completion(nil) }
guard let rawInventory = response.result.value as? [[String: Any]?] else { return completion(nil) }
let inventory = rawInventory.compactMap { pizzaDict -> Drink? in
var data = pizzaDict!
data["image"] = UIImage(named: pizzaDict!["image"] as! String)
//print("Printing each item: ", Drink(data: data))
//printing all inventory successful
return Drink(data: data)
}
completion(inventory)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("ROWS: ", drinks.count)
return drinks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell
//let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")
let cell:DrinkTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! DrinkTableViewCell
//cell.cellName?.text = drinks[indexPath.row].name
//cell.cellAmount?.text = String(drinks[indexPath.row].amount)
//cell.cellDescription?.text = drinks[indexPath.row].description
//cell.cellImage?.image = drinks[indexPath.row].image
cell.imageView?.image = drinks[indexPath.row].image
cell.textLabel?.text = drinks[indexPath.row].name
cell.detailTextLabel?.text = drinks[indexPath.row].description
//print(cell.textLabel?.text)
//print(cell.detailTextLabel?.text)
print(cell.cellName?.text as Any)
//print(cell.cellImage?.image)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
}
}
From your comment:
. I have a button in the tabBarController that presents the tableView and this is working fine.
let drinkController = DrinkListTableViewController()
let drinkNavigationController = UINavigationController(rootViewController: drinkController)
self.present(drinkNavigationController, animated: true, completion: nil)
No it isn’t working fine. It is the problem.
Basically this is the same situation as in my answer here:
https://stackoverflow.com/a/40077530/341994
You are obtaining a useless instance when you say DrinkListTableViewController(). What you need to do is talk to the storyboard and ask it to instantiate the desired view controller (by identifier) so that you get the instance from the storyboard, the one that has the segue.

UITableView won't display information from array

So I'm trying to create a tableview and a cell won't show up. Other than not appending anything to the recipes array, is there anything blatantly wrong with my code?
If this means anything, when I try to link the tableview to my code, it doesn't give me the opportunity to create an outlet. Github link here
I'm New to iOS programming so this might be a dumb question, sorry if that's the case.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var recipes : [Recipe] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let recipe = recipes[indexPath.row]
cell.textLabel?.text = recipe.title!
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipes.count
}
func createRecipe() -> [Recipe] {
let recipe1 = Recipe()
recipe1.title = "Test"
recipe1.instructions = "testing"
recipe1.time = "testing"
let recipe2 = Recipe()
recipe2.title = "Test2"
recipe2.instructions = "testing"
recipe2.time = "testing"
return [recipe1, recipe2]
}
}
Thanks.
You need to assign Recipe Class Array in viewDidLoad and In cellForAt assign UITableviewCell
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
recipes = createRecipe()
tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
let recipe = recipes[indexPath.row]
cell.textLabel?.text = recipe.title!
return cell
}
Where are you calling createRecipe()? Where are you adding recipes to your recipes array? I think what you meant was to write recipes = createRecipe() in your viewDidLoad. Additionally to be sure your tableView is loaded with the latest data, add tableView.reloadData()
as well.
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
recipes = createRecipe()
tableView.reloadData()
}
Otherwise your recipe is would be just an empty array which translates to 0 rows...
Actually the problem is within your storyboard. Your controller is not ViewController is a basic UIViewController. So you need to change the type from UIViewController to ViewController and link your tableView after. That's why I didn't work when you were trying to link it the first time. I uploaded an image to be clear.
I wasn't saving to coreData as the Recipe class was created in coreData, and I wasn't saving anything from the createRecipe function.
Here's the fixes
New Function:
func getRecipes() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
recipes = try context.fetch(Recipe.fetchRequest()) as! [Recipe]
print(recipes)
} catch {
print("ERROR")
}
}
Revised createRecipe()
func createRecipe() -> [Recipe] {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let recipe3 = Recipe(context: context)
recipe3.title = "test3"
recipe3.instructions = "testing"
recipe3.time = "testing"
(UIApplication.shared.delegate as! AppDelegate).saveContext()
navigationController!.popViewController(animated: true)
return [recipe3]
}
And the viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
recipes = createRecipe()
getRecipes()
}