UITableView won't update - swift

After going through about a thousand SO questions, I've given up and am reaching out for help. I have a very straightforward table using custom cells. When a button is pushed, a new item is added to the array, and the table should update to show the new item. That's not happening. The data is all moving correctly but the only way to get the table to update is to quit and relaunch the app. Code below with unnecessary sections about defining variables, etc. removed. Thanks!
UPDATE: I have deleted, recreated, and relinked the table and prototype cell with no change.
class DispatchTableViewCell: UITableViewCell {
#IBOutlet weak var routeLabel: UILabel!
#IBOutlet weak var aircraftLabel: UILabel!
#IBOutlet weak var altitudeLabel: UILabel!
#IBOutlet weak var speedLabel: UILabel!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var departureTimeLabel: UILabel!
#IBOutlet weak var arrivalTimeLabel: UILabel!
#IBOutlet weak var remainingTimeLabel: UILabel!
#IBOutlet weak var progressBar: UIProgressView!
}
class DispatchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var flightsTableView: UITableView!
#IBAction func dispatchButton(_ sender: Any) {
flightsTableView.beginUpdates()
// Do all the things to update the array
// Works fine, array is correct
flightsTableView.endUpdates()
}
let realm = try! Realm()
var flightsArray: [Flight] = []
var originsArray: [String] = []
var destinationsArray: [String] = []
var aircraftNamesArray: [String] = []
var departureTimesArray: [Date] = []
var arrivalTimesArray: [Date] = []
var speedsArray: [Double] = []
var altitudesArray: [Double] = []
override func viewDidLoad() {
flightsTableView!.dataSource = self
flightsTableView!.delegate = self
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
flightsTableView.beginUpdates()
for flight in realm.objects(Flight.self) {
flightsArray.append(flight)
}
for flight in flightsArray {
originsArray.append(flight.originCode)
destinationsArray.append(flight.destinationCode)
aircraftNamesArray.append(flight.aircraftNameShort)
departureTimesArray.append(flight.departureTime)
arrivalTimesArray.append(flight.arrivalTime)
speedsArray.append(flight.cruiseSpeed)
altitudesArray.append(flight.cruiseAltitude)
}
flightsTableView.endUpdates()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return flightsArray.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 90
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "flight", for: indexPath) as! DispatchTableViewCell
let origin = originsArray[indexPath.row]
let destination = destinationsArray[indexPath.row]
cell.routeLabel?.text = "\(origin) -> \(destination)"
print(cell.routeLabel)
cell.aircraftLabel?.text = aircraftNamesArray[indexPath.row]
cell.altitudeLabel?.text = "Altitude: \(Int(altitudesArray[indexPath.row]))"
cell.speedLabel?.text = "Speed: \(Int(speedsArray[indexPath.row]))"
cell.statusLabel?.text = "Test"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "h:mm a"
dateFormatter.timeZone = TimeZone.current
//tempFlight.departureTime = dateFormatter.string(from: tempFlight.departureTime)
//tempFlight.arrivalTime = dateFormatter.string(from: tempFlight.arrivalTime)
cell.departureTimeLabel?.text = dateFormatter.string(from: departureTimesArray[indexPath.row])
cell.arrivalTimeLabel?.text = dateFormatter.string(from: arrivalTimesArray[indexPath.row])
return cell
}
}

.beginUpdates()/.endUpdates() does not actually cause table view to reload the content it displays.
You are updating the data source and, you should let table view know about the changes by calling .reloadData() so it will ask the data source for the changes you've made and reorganize its own content:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
for flight in realm.objects(Flight.self) {
flightsArray.append(flight)
}
for flight in flightsArray {
originsArray.append(flight.originCode)
destinationsArray.append(flight.destinationCode)
aircraftNamesArray.append(flight.aircraftNameShort)
departureTimesArray.append(flight.departureTime)
arrivalTimesArray.append(flight.arrivalTime)
speedsArray.append(flight.cruiseSpeed)
altitudesArray.append(flight.cruiseAltitude)
}
flightsTableView.reloadData()
}

I was calling .reloadData() in the button func but I was not retrieving fresh data from Realm.

Related

Label Data lost when scrolling in UITableView

I made a table view with a label that increments and decrements on pressing a button and another button to show the text in another label outside the UItableView. Everything works fine but when I scroll the Tableview the value resets to zero!
Before Scrolling
After Scrolling
My ViewController class
class ViewController: UIViewController{
var numArray = [Value]()
var initialValue = 0
#IBOutlet weak var tableView : UITableView!
#IBOutlet weak var lblOutput : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
for _ in 0 ... 100{
numArray.append(Value(number: initialValue))
}
self.lblOutput.text = "\(initialValue)"
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
}
}
extension ViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",for: indexPath) as? ControllerTableViewCell else{fatalError("Error in creating cells")}
cell.delegate = self
cell.data = numArray[indexPath.row]
cell.lblInput.text = "\(cell.data.number)"
return cell
}
}
extension ViewController : MyTableViewCellDelegate{
func DidPrint(Data: String) {
self.lblOutput.text = "\(Data)"
}
}
My TableViewCell class
protocol MyTableViewCellDelegate : AnyObject {
func DidPrint(Data: String)
}
class ControllerTableViewCell: UITableViewCell {
weak var delegate : MyTableViewCellDelegate?
var data : Value!
private var counterValue = 0
#IBOutlet var lblInput : UILabel!
#IBOutlet var btnPrint : UIButton!
#IBOutlet var btnPlus : UIButton!
#IBOutlet var btnMinus : UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func DidPressPrint(){
self.data.number = counterValue
delegate?.DidPrint(Data: "\(data.number)")
print(data.number)
}
#IBAction func DidPressPlus(){
counterValue += 1
data.number = counterValue
self.lblInput.text = "\(data.number)"
}
#IBAction func DidPressMinus(){
if(counterValue > 0){
counterValue -= 1
data.number = counterValue
}
else{
counterValue = 0
data.number = 0
}
self.lblInput.text = "\(data.number)"
}
}
My Data Model
import Foundation
struct Value{
var number : Int
}
As #El Tomato suggested, you are not updating your data source, that's why your changes gets "forgotten" on scroll.
Try to move your didPressPlus, didPressMinus and didPressPrint in your ViewController class and redefine your table view delegate like below.
By passing the tag attributes to the buttons, you can then retrieve the index of the item pressed in the functions and edit the correct data source item.
Also remove the unnecessary MyTableViewCellDelegate.
class ViewController: UIViewController{
var numArray = [Value]()
var initialValue = 0
#IBOutlet weak var tableView : UITableView!
#IBOutlet weak var lblOutput : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
for _ in 0 ... 100 {
numArray.append(Value(number: initialValue))
}
self.lblOutput.text = "\(initialValue)"
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController : UITableViewDelegate, UITableViewDataSource
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? ControllerTableViewCell else {fatalError("Error in creating cells")}
let indexItem = indexPath.row
let valueItem = numArray[indexItem]
cell.lblInput.text = valueItem.number
cell.btnMinus.tag = indexItem
cell.btnMinus.addTarget(self, action: #selector(didPressMinus(_:)), for: .touchUpInside)
cell.btnPlus.tag = indexItem
cell.btnPlus.addTarget(self, action: #selector(didPressPlus(_:)), for: .touchUpInside)
cell.btnPrint.tag = indexItem
cell.btnPrint.addTarget(self, action: #selector(didPressPrint(_:)), for: .touchUpInside)
return cell
}
#objc private func didPressPlus(_ sender: UIButton) {
let dataIndex = sender.tag
if numArray.count < dataIndex { return }
let numArrayItem = numArray[dataIndex]
if (numArrayItem.number >= 0) {
numArray[dataIndex].number -= 1
}
tableView.reloadData()
}
#objc private func didPressMinus(_ sender: UIButton) {
let dataIndex = sender.tag
if numArray.count < dataIndex { return }
numArray[dataIndex].number += 1
tableView.reloadData()
}
#objc private func didPressPrint(_ sender: UIButton) {
let dataIndex = sender.tag
if numArray.count < dataIndex { return }
self.lblOutput.text = "\(numArray[dataIndex].number)"
}
}
In order to move the three methods in the ViewController you'll need to remove the two correspondent IBAction from the UITableViewCell class.
Also, remove the linkage with the ControllerTableViewCell actions.
Here is the resulting ControllerTableViewCell:
class ControllerTableViewCell: UITableViewCell {
#IBOutlet var lblInput : UILabel!
#IBOutlet var btnPrint : UIButton!
#IBOutlet var btnPlus : UIButton!
#IBOutlet var btnMinus : UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
}
Your TableView's numberOfRowsInSection is using numArray as a source (numArray.count) and so is your cellForRowAt function, but your cell functions are updating your 'data' variable. Your 'data' variable is locally defined to your tableView and gets reset every time it is activated (including when you scroll).
You need to update the numArray or some other global resource to make it work. This involves using indexpath of the cell value inside the cell functions, meaning you need a way to refer to indexPath inside the cell. This article explains how to use tags or delegates, https://fluffy.es/handling-button-tap-inside-uitableviewcell-without-using-tag/.
Here's a solution using the existing delegate.
import UIKit
import Foundation
var initialValue = 0
var numArray = Array(repeating: initialValue, count: 100)
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var lblOutput: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.lblOutput.text = "\(initialValue)"
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
// Do any additional setup after loading the view.
}
}
extension ViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",for: indexPath) as? ControllerTableViewCell else{fatalError("Error in creating cells")}
cell.indexPath = indexPath
cell.delegate = self
cell.lblInput.text = String(numArray[indexPath.row])
return cell
}
}
extension ViewController : MyTableViewCellDelegate{
func DidPrint(Data: String) {
self.lblOutput.text = "\(Data)"
}
}
protocol MyTableViewCellDelegate : AnyObject {
func DidPrint(Data: String)
}
class ControllerTableViewCell: UITableViewCell {
weak var delegate : MyTableViewCellDelegate?
var indexPath : IndexPath?
private var counterValue = 0
#IBOutlet var lblInput : UILabel!
#IBOutlet var btnPrint : UIButton!
#IBOutlet var btnPlus : UIButton!
#IBOutlet var btnMinus : UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func DidPressPrint(){
delegate?.DidPrint(Data: "\(numArray[indexPath!.row])")
}
#IBAction func DidPressPlus(){
numArray[indexPath!.row] = numArray[indexPath!.row] + 1
self.lblInput.text = "\(numArray[indexPath!.row])"
}
#IBAction func DidPressMinus(){
if(numArray[indexPath!.row] > 0){
numArray[indexPath!.row] = numArray[indexPath!.row] - 1
}
else{
numArray[indexPath!.row] = 0
}
self.lblInput.text = "\(numArray[indexPath!.row])"
}
}

"Fatal error: Index out of range 2019-08-30 11:01:35.001667-0400 fmcBeta[58563:3478851] Fatal error: Index out of range"

I am creating an events feed, using a table view and Firebase as my database. I am using dateformatter with a style type of full for date and short for time and writing it to my database as a string which is perfect, it writes exactly how i want it to.
However, when i try to read the data from firebase and display it on my textlabel in the tableview cell i get the following error.
Error:
"Fatal error: Index out of range
2019-08-30 11:01:35.001667-0400 fmcBeta[58563:3478851] Fatal error: Index out of range"
Any help would be greatly appreciated i am self learning and fairly new to swift.
This is my table view cell:
class EventsTableViewCell: UITableViewCell {
#IBOutlet weak var eventLocation: UILabel!
#IBOutlet weak var eventDate: UILabel!
#IBOutlet weak var eventTitle: UILabel!
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
}
}
This is my viewcontoller with tableview protocols:
class EventsViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var eventsRef: DatabaseReference?
var eventsDatabaseHandle:DatabaseHandle?
var eventsTitles = [String]()
var eventTimestamps:[String] = []
var eventsLocations = [String]()
eventsRef = Database.database().reference()
tableView.reloadData()
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
tableView.delegate = self
tableView.dataSource = self
eventsDatabaseHandle = eventsRef?.child("Church Events").observe(.childAdded, with: { (snaphot) in
let eventPost = snaphot.value as! [String: Any]
self.eventTimestamps.append(eventPost["eventdate"] as! String)
self.eventsTitles.append(eventPost["eventtitle"] as! String)
self.eventsLocations.append(eventPost["eventlocation"] as! String)
self.tableView.reloadData()
})
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return eventsTitles.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "events") as! EventsTableViewCell
cell.eventTitle.text! = eventsTitles[indexPath.row]
cell.eventDate.text! = eventTimestamps[indexPath.row]
cell.eventLocation.text! = eventsLocations[indexPath.row]
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
return cell
}
}
This is how i'm writing the data to Firebase
#IBAction func saveEventsButton(_ sender: Any) {
let eventsDates = DateFormatter.localizedString(from: eventDateSelector.date, dateStyle: DateFormatter.Style.full, timeStyle: DateFormatter.Style.short) as String
print(eventsDates.description)
let eventSaved:[String: Any] = ["eventdate": eventsDates,"eventtitle":eventsTitleTextField.text!,"eventlocation":eventsLocation.text!]
eventsRef.child("Church Events").childByAutoId().setValue(eventSaved)
self.dismiss(animated: true, completion: nil)
}
}

Autoresize static cell by overweight label

I have some static cells and this don't want to change their size by overweight content in label. I have all constraints(top, bottom, leading,tralling) in each cells, also I have this code:
import UIKit
class FilmTableViewController: UITableViewController {
#IBOutlet weak var posterView: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var yearLabel: UILabel!
#IBOutlet weak var directorLabel: UILabel!
#IBOutlet weak var actorsLabel: UILabel!
#IBOutlet weak var countryLabel: UILabel!
#IBOutlet weak var plotLabel: UILabel!
#IBOutlet weak var RatingLabel: UILabel!
private let networkingService = NetworkingService()
var filmImbdbID = ""
override func viewDidLoad() {
super.viewDidLoad()
loadFilm(filmImbdbID)
}
override func viewDidAppear(_ animated: Bool) {
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 80
}
private func loadFilm(_ film: String) {
networkingService.fetchFilmRecording(matching: film) { [weak self] response in
guard let `self` = self else {
return
}
self.directorLabel.text = response.recordings?.director
self.titleLabel.text = response.recordings?.title
self.yearLabel.text = response.recordings?.year
self.actorsLabel.text = response.recordings?.actors
self.countryLabel.text = response.recordings?.country
self.plotLabel.text = response.recordings?.plot
self.RatingLabel.text = response.recordings?.rating
if let imageUrl = URL(string: response.recordings!.poster) {
guard let data = try? Data(contentsOf: imageUrl) else { return }
let image = UIImage(data: data)
self.posterView.image = image
}
}
}
}
Also numberOfLines is 0.
When I see this view, it don't work, however if I slide down it looks like this:
Please, some idea to fix it? :(
You need to update your code, cause is not clear what's happening.
Anyway you should use or:
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 80
or delegate methods
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableView.automaticDimension
}
not both

how to pass data retrieve from firebase in Table VIew Controller to View Controller

I am building a car sharing IOS App prototype. My app is link to firebase, i can retrieve and display journey data in a table view but when trying to pass the data in another view controller the data do not display. Below are my table View controller and view controllers source codes.
import UIKit
import Firebase
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var myIndex = 0
var journeyList = [journeyModel]()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return journeyList.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
// defining firebase reference var
var refjourney: DatabaseReference!
#IBOutlet weak var journeyTable: UITableView!
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell", for: indexPath as IndexPath) as! journeySearchTableViewCell
var journe: journeyModel
journe = journeyList[indexPath.row]
print(journe.start!, journe.destination!, journe.date!, journe.driverName!)
cell.driverNameLabel.text = journe.driverName
cell.startLabel.text = journe.start
cell.destinationLabel.text = journe.destination
cell.dateLabel.text = journe.date
return cell
}
At this point the app functions correctly only faces issues when passing the data to another view controller
override func viewDidLoad() {
super.viewDidLoad()
Database.database().reference().child("Journey").observe(.value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
self.journeyList.removeAll()
for journey in snapshot.children.allObjects as! [DataSnapshot] {
let journeyObject = journey.value as? [String: AnyObject]
let start = journeyObject?["startingPoint"]
let destination = journeyObject?["destinationPoint"]
let driverName = journeyObject?["driverName"]
let date = journeyObject?["tripDate"]
let id = journeyObject?["id"]
let journey = journeyModel(destination: destination as! String?, driverName: driverName as! String?, start: start as! String?, date: date as! String?, uid: id as! String?)
self.journeyList.append(journey)
}
self.journeyTable.reloadData()
}
})
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "logged", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var bsVC: bookSetViewController = segue.destination as! bookSetViewController
}
#IBAction func backButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
import UIKit
class bookSetViewController: UIViewController {
var getStart = String()
var getStop = String()
var getDate = String()
var getDriver = String()
#IBOutlet weak var startingLabel: UILabel!
#IBOutlet weak var stopingLabel: UILabel!
#IBOutlet weak var daterLabel: UILabel!
#IBOutlet weak var driveLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
startingLabel.text! = getStart
stopingLabel.text! = getStop
daterLabel.text! = getDate
driveLabel.text! = getDriver
}
}
import UIKit
class journeySearchTableViewCell: UITableViewCell {
#IBOutlet weak var startLabel: UILabel!
#IBOutlet weak var destinationLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var driverNameLabel: UILabel!
}
import UIKit
class journeyModel: NSObject {
var driverName: String?
var start: String?
var destination: String?
var date: String?
var uid: String?
init(destination: String?, driverName: String?, start: String?, date: String?, uid: String?) {
self.driverName = driverName
self.start = start
self.destination = destination
self.date = date
self.uid = uid
}
}
First things, first - don't share the whole project, just the bits that are needed.
The whole point of the prepare(for segue... is to get a handle to the new controller, and assign the values you need to pass over.
You will need to keep a track of which journey you're interested in. There are many ways to do this, but the easiest might be to extend what you do on the click row
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
// assume you have defined journeySelected as a class-level instance of journeyModel
journeySelected = journeyModel[indexPath.row]
performSegue(withIdentifier: "logged", sender: self)
}
and then
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var bsVC: bookSetViewController = segue.destination as! bookSetViewController
bsVC.getStart = journeySelected.start
// and for all the other fields
}

TableView within TableviewCell not displaying cells

I have a UITablaView inside UITableviewCell. Here is my code:
UITableViewCell:
class ProductViewCell: UITableViewCell {
#IBOutlet weak var totalOrderButton: UIButton!
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productSubNameLabel: UILabel!
#IBOutlet weak var productBioLabel: UILabel!
#IBOutlet weak var mlButton: UIButton!
#IBOutlet weak var productQuantity: UILabel!
#IBOutlet weak var plusButton: UIButton!
#IBOutlet weak var minusButton: UIButton!
#IBOutlet weak var greenHeartButton: UIButton!
#IBOutlet weak var liquorsTableView: UITableView!
var fourLiquorStores: [LiquorStore] = []
var currentUser: User!
var currentProduct: Product! {
didSet {
updateUI()
}
}
func updateUI() {
downloadProductImage()
productNameLabel.text = currentProduct.name
productSubNameLabel.text = currentProduct.subName
productBioLabel.text = currentProduct.description
productQuantity.text = "\(currentProduct.quantity)"
updateGreenHeart()
}
var cache = SAMCache.shared()
weak var delegate: ProductViewCellDelegate!
override func awakeFromNib() {
super.awakeFromNib()
liquorsTableView.estimatedRowHeight = 65
liquorsTableView.rowHeight = 65
liquorsTableView.delegate = self
liquorsTableView.dataSource = self
fetchLiquorStores()
}
func fetchLiquorStores() {
LiquorStore.observeNewLiquorStore { (liquorStore) in
LiquorStore.observeNewLiquorStore { (liquorStore) in
if !self.fourLiquorStores.contains(liquorStore) {
self.fourLiquorStores.append(liquorStore)
self.delegate.updateTableView()
print(self.fourLiquorStores)
}
}
}
}
func downloadProductImage() {
let productuid = currentProduct.uid
let profileImageKey = "\(productuid)"
if let image = cache?.object(forKey: profileImageKey) as? UIImage {
productImage.image = image
} else {
currentProduct.downloadPopularProductImage { [weak self] (image, error) in
if let error = error {
print(error.localizedDescription)
} else {
self?.productImage.image = image
self?.cache?.setObject(image, forKey: profileImageKey)
}
}
}
}
// Ad o delete Quantities
#IBAction func plusDidTap() {
if currentProduct.quantity >= 1 && currentProduct.quantity <= 60 {
currentProduct.quantity += 1
delegate.updateTableView()
}
}
#IBAction func minusDidTap() {
if currentProduct.quantity > 1 {
currentProduct.quantity -= 1
delegate.updateTableView()
}
}
func updateGreenHeart() {
if let currentUser = currentUser {
if currentUser.favoriteProducts.contains(currentProduct) {
greenHeartButton.setImage(#imageLiteral(resourceName: "GreenHeartFilled"), for: [])
} else {
greenHeartButton.setImage(#imageLiteral(resourceName: "GreenHeart"), for: [])
}
}
}
// Ad or delete Favorite Products
#IBAction func greenHeartDidTap() {
if currentUser.favoriteProducts.contains(currentProduct) {
self.greenHeartButton.setImage(#imageLiteral(resourceName: "GreenHeart"), for: [])
self.currentUser.deleteFavoriteProduct(product: currentProduct)
} else {
self.greenHeartButton.setImage(#imageLiteral(resourceName: "GreenHeartFilled"), for: [])
self.currentUser.addFavoriteProduct(product: currentProduct)
}
}
}
extension ProductViewCell: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return fourLiquorStores.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = liquorsTableView.dequeueReusableCell(withIdentifier: "LiquorStoreViewCell", for: indexPath) as! LiquorStoresViewCell
cell.currentProduct = self.currentProduct
cell.liquorStore = self.fourLiquorStores[indexPath.section]
return cell
}
}
UITablViewCell -2 :
class LiquorStoresViewCell: UITableViewCell {
#IBOutlet weak var liquorStoreNameLabel: UILabel!
#IBOutlet weak var liquorStorePriceLabel: UILabel!
#IBOutlet weak var liquorStoreTimeLabel: UILabel!
#IBOutlet weak var starStackView: UIStackView!
#IBOutlet weak var imageViewBoard: UIImageView!
var currentProduct: Product!
var currentPriceIndex: Int = 0
var liquorStore: LiquorStore! {
didSet {
updateUI()
}
}
func updateUI() {
changeLiquorStoreProductsUid()
liquorStoreNameLabel.text = liquorStore.userName
let index = liquorStore.products.index(of: currentProduct)
if let index = index {
let productPrice = liquorStore.products[index].price[currentPriceIndex]
format(price: productPrice)
}
}
// Format Product Price to Currency
func format(price: Double) {
let formatter = NumberFormatter()
formatter.locale = Locale.current // Change this to another locale if you want to force a specific locale, otherwise this is redundant as the current locale is the default already
formatter.numberStyle = .currency
if let formattedTipAmount = formatter.string(from: price as NSNumber) {
liquorStorePriceLabel.text = "Tip Amount: \(formattedTipAmount)"
}
}
// Func to organize LiquorStores
func changeLiquorStoreProductsUid () {
for product in liquorStore.products {
if self.currentProduct.name == product.name && self.currentProduct.description == product.description && self.currentProduct.subName == product.subName {
let index = liquorStore.products.index(of: product)
if let index = index {
liquorStore.products[index].uid = currentProduct.uid
}
}
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
liquorStorePriceLabel.textColor = UIColor.white
liquorStoreNameLabel.textColor = UIColor.white
liquorStoreTimeLabel.textColor = UIColor.white
imageViewBoard.backgroundColor = #colorLiteral(red: 0.5239839702, green: 0.5239839702, blue: 0.5239839702, alpha: 1)
for view in starStackView.subviews {
let image = view as! UIImageView
image.image = #imageLiteral(resourceName: "WhiteStar")
}
}
}
The UITableView inside the UITableviewCell doesn't show the data :/
What's the problem?
This is what I'm building:
StoryBoard
An this appears in the simulator, as you can see, the second tableview is empty:
Simulator
PD: I'm downloading successfully the liquorStores from firebase.
While it's possible to do what you are trying to do, it would be much simpler to rethink your architecture entirely. If your view controller displays only a single product, plus a list of liquor stores, then the product view shouldn't really be in a cell at all--just make it an ordinary view, and make that view your table's header. The cells will then be the liquor stores, and you no longer have to deal with nesting a table within a cell. Alternately, you can keep the product view in a cell, but just add prototypes for the liquor stores as a second kind of cell in the same table.
EDIT: Now that you've posted your storyboard screenshot, the easiest thing for you to do is to move your liquor store prototype cell up to the top-level table, remove the subtable from the top-level cell, and in your data source, have
func tableView(_ tableView: UITableView, cellForRowAtIndexPath path: NSIndexPath) -> UITableViewCell {
if path.row == 0 {
return tableView.dequeueCellWithIdentifier("productDetailsCell")!
} else {
return tableView.dequeueCellWithIdentifier("liquorStoreCell")!
}
}