How pass data from button in TableViewCell to View Controller? - swift

I have 2 ViewControllers, one of is called ProductListVC the other is MoreInfoVC. I have a tableView on ProductListViewController that shows cells multiple labels and buttons.
MoreInfoVC is a Modal pop-up VC with a few labels for the brand, Name, and description. I have all my data stored in Firestore and already have created class(ProductList) to help retrieve the data which presents the data in the tableview from the Cloud Firestore.
what I need to do is use the MoreInfo button in the individual TBV cell to pass the data into MoreInfoVC so that it can present the information of selected product
Now i can easily do this with either didSelectRowAt method or using indexPathForSelectedRow in prepare segue method. But both cases requires me to tap on the cell itself but not the button.
how would I be able to pass data from an individual tableview cell through the MoreInfo button onto the MoreInfoVC. I think I'm on the right path since it seems my MoreInfoVC is passing data but showing this at the moment
import UIKit
import Firebase
import FirebaseFirestore
class ProductListVC: UIViewController {
#IBOutlet weak var productListTableView: UITableView!
var productInventory: [ProductList] = []
var productSetup: [ProductList] = []
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
productListTableView.dataSource = self
productListTableView.delegate = self
searchBar.delegate = self
fetchProducts { (products) in
self.productSetup = products
self.productListTableView.reloadData()
}
}
func fetchProducts(_ completion: #escaping ([ProductList]) -> Void) {
let ref = Firestore.firestore().collection("products")
ref.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
}
}
}
extension ProductListVC: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
ProductListCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
cell.delegate = self
return cell
}
}
extension ProductListVC: ProductListCellDelegate {
func onTouchInfoButton(from cell: ProductListCell) {
self.selectedProduct = cell.product
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
self.performSegue(withIdentifier: "MoreInfo", sender: self)
}
}
import UIKit
import Firebase
class MoreInfoVC: UIViewController {
var products: ProductList?
#IBOutlet weak var productName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
productName.text = "\(String(describing: products?.brand)): \(String(describing: products?.name))"
}
#IBAction func closeBtn(_ sender: Any) {
dismiss(animated: true, completion: nil)
print("Close More Information")
}
}
import UIKit
import SDWebImage
import Firebase
protocol ProductListCellDelegate: class {
func onTouchInfoButton(from cell: ProductListCell)
}
class ProductListCell: UITableViewCell {
weak var product: ProductList!
weak var delegate: ProductListCellDelegate?
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var productName: UILabel!
#IBOutlet weak var categoryLabel: UILabel!
#IBOutlet weak var strain: UILabel!
#IBOutlet weak var moreInfo: RoundButton!
func configure(withProduct product: ProductList) {
productName.text = "\(String(describing: product.brand)): \(String(describing: product.name))"
categoryLabel.text = product.category
productImage.sd_setImage(with: URL(string: product.imageUrl))
strain.text = product.strain
self.product = product
}
#IBAction func infoButtonAction(_ sender: Any) {
self.delegate?.onTouchInfoButton(from: self)
}
}

Function #IBAction func infoButtonAction(_ sender: Any) {} should be in the ProductListCell
When that button is tapped, connect with the ProductListVC by delegate or closure to get the selected product.
Update
Using delegate:
Update your ProductListCell
import UIKit
import SDWebImage
import Firebase
protocol ProductListCellDelegate: class {
func onTouchInfoButton(from cell: ProductListCell)
}
class ProductListCell: UITableViewCell {
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var dispensaryName: UILabel!
#IBOutlet weak var productName: UILabel!
#IBOutlet weak var thcPercent: UILabel!
#IBOutlet weak var cbdPercent: UILabel!
#IBOutlet weak var categoryLabel: UILabel!
#IBOutlet weak var categoryStrain: UILabel!
#IBOutlet weak var moreInfo: RoundButton!
weak var product: Product!
weak var delegate: ProductListCellDelegate?
func configure(withProduct product: ProductList) {
self.product = product
productName.text = "\(String(describing: product.brand)): \(String(describing: product.name))"
dispensaryName.text = product.dispensaryName
categoryLabel.text = product.category
productImage.sd_setImage(with: URL(string: product.imageUrl))
cbdPercent.text = product.cbd
thcPercent.text = product.thc
categoryStrain.text = product.strain
}
#IBAction func infoButtonAction(_ sender: Any) {
self.delegate?.onTouchInfoButton(from: self)
}
}
In your ProductListVC:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
ProductListCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
cell.delegate = self
return cell
}
extension ProductListVC: ProductListCellDelegate {
func onTouchInfoButton(from cell: ProductListCell) {
let selectedProduct = cell.product
// Do your stuff here
}
}
UPDATE
Because you use segue for navigation so let's create a variable to store your selected product in your ProductListVC
import UIKit
import Firebase
import FirebaseFirestore
class ProductListVC: UIViewController {
#IBOutlet weak var productListTableView: UITableView!
var productInventory: [ProductList] = []
var productSetup: [ProductList] = []
var selectedProduct: Product?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
productListTableView.dataSource = self
productListTableView.delegate = self
searchBar.delegate = self
fetchProducts { (products) in
self.productSetup = products
self.productListTableView.reloadData()
}
}
func fetchProducts(_ completion: #escaping ([ProductList]) -> Void) {
let ref = Firestore.firestore().collection("products")
ref.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? MoreInforVC {
vc.product = self.selectedProduct
}
}
}
extension ProductListVC: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
ProductListCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
cell.delegate = self
return cell
}
}
extension ProductListController: ProductListCellDelegate {
func onTouchInfoButton(from cell: ProductListCell) {
self.selectedProduct = cell.product
self.performSegue(withIdentifier: "YourSegueIdentifier", sender: self)
}
}

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])"
}
}

Updating Realm through a custom button on the UITableViewCell

I have a tableview of "Books" that are stored in Realm. I want to set the "CurrentBook" property to "True" when hitting a button on a custom UITableViewCell.
I believe my error has something to do with getting the correct book value in "func selectCurrentBook", when I use an optional like below nothing happens.
#objc func selectCurrentBook(sender: UIButton) {
try! realm.write {
book?.currentlyReading = true
}
}
When I don't use an optional for book and use book.currentlyReading = true I get the error "Unexpectedly found nil while implicitly unwrapping an Optional value:"
Am I incorrectly passing the book value somewhere? I can't seem to find out how. Maybe I'm delegating wrong?
My TableViewCell is:
import UIKit
import RealmSwift
protocol MyBooksDelegate {
func currentlyReadingButton()
}
class MyBooksTableViewCell: UITableViewCell {
let realm = try! Realm()
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var authorLabel: UILabel!
#IBOutlet weak var smallThumbnailImageView: UIImageView!
#IBOutlet weak var currentlyReadingButton: UIButton!
#IBAction func currentlyReadingButton(_ sender: Any) {
}
private var book: Book!
func loadImage(smallThumbnailURL: String) {
let imageURL = URL(string: smallThumbnailURL ?? "")
smallThumbnailImageView.sd_setImage(with: imageURL)
}
func configureCell(book: Book, delegate: MyBooksDelegate?) {
titleLabel.text = book.bookTitle
authorLabel.text = book.bookAuthor
loadImage(smallThumbnailURL: book.bookSmallThumbnailImageURL)
currentlyReadingButton.addTarget(self, action: #selector(selectCurrentBook(sender:)), for: .touchUpInside)
}
#objc func selectCurrentBook(sender: UIButton) {
try! realm.write {
book?.currentlyReading = true
}
}
}
My View Controller with TableView is :
import SwiftyJSON
import RealmSwift
class BooksViewController: UIViewController, UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var myBooksTableView: UITableView!
let realm = try! Realm()
var books: Results<Book>?
// Search Bar Properties
var searchParameter = "intitle"
var booksArray: [Book] = []
override func viewDidLoad() {
super.viewDidLoad()
loadBooks()
// Setting up the TableView
self.myBooksTableView.delegate = self
self.myBooksTableView.dataSource = self
self.myBooksTableView.rowHeight = 120.0
// Setup Title
title = "My Books"
// navigationController?.navigationBar.prefersLargeTitles = true
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.navigationBar.barStyle = .black
loadBooks()
}
func loadBooks() {
books = realm.objects(Book.self).sorted(byKeyPath: "DateCreated", ascending: false)
myBooksTableView.reloadData()
}
// TABLEVIEW
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return books?.count ?? 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MyBooksTableViewCell", for: indexPath) as? MyBooksTableViewCell {
cell.configureCell(book: (books?[indexPath.row])!, delegate: self as? MyBooksDelegate)
// cell.selectionStyle = UITableViewCell.SelectionStyle.none
return cell
} else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "myBooksTOMyBooksDetail", sender: self)
myBooksTableView.deselectRow(at: indexPath, animated: true)
}
And my Book Model is:
class Book: Object {
#objc dynamic var bookTitle: String!
#objc dynamic var bookAuthor: String!
#objc dynamic var bookSmallThumbnailImageURL: String!
#objc dynamic var bookThumbnailImageURL: String!
#objc dynamic var bookDescription: String!
#objc dynamic var bookISBN_13: String!
#objc dynamic var currentlyReading = false
#objc dynamic var DateCreated = Date()
#objc dynamic var WordID = UUID().uuidString
// words
let words = List<Word>()
override static func primaryKey() -> String? {
return "WordID"
}
}
The most compatible syntax is
currentlyReadingButton.addTarget(self, action: #selector(selectCurrentBook), for: .touchUpInside)
and
#objc func selectCurrentBook(_ sender: UIButton) {
However as the cell is custom anyway I'd prefer an IBAction over target/action
And the protocol MyBooksDelegate seems to be unused.
Side note:
Force unwrap the cell
let cell = tableView.dequeueReusableCell(withIdentifier: "MyBooksTableViewCell", for: indexPath) as! MyBooksTableViewCell
A crash – with report – reveals a design mistake which can be fixed instantly. With the if let you'll see nothing and have no clue why.
Update:
The crash occurs because you don't set book in the cell, add the first line after the {
func configureCell(book: Book, delegate: MyBooksDelegate?) {
self.book = book
titleLabel.text = book.bookTitle
...

How can I get user to input text in a text field inside a xib cell in swift

I have created a xib cell with two textfields. The textfield are connected as IBoutlets to the xib swift file. The xib cell is registered on the view controller as a Nib. When I run the app on a simulator I cannot get the keyboard to show up. Secondly, the textfields are not editable at all, that is the cursor doesn't even show. I would like to get help with this as I have tried using a label the same thing happens. I'm just not sure how to fix this one. I'm not getting errors on build. I have installed IQKeyboardManager from cocoapods. Thanks in advance.
Heres the code:
import UIKit
class DictionaryCell: UITableViewCell {
#IBOutlet weak var DictBubble: UIView!
#IBOutlet weak var DictSymbolTextfield: UITextField!
#IBOutlet weak var SymbolMeaningTextfield: UITextView!
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
}
}
Here is the view controller code:
import UIKit
import Firebase
class PersonalDreamDictionaryViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var dictionaryTextfield: UITextField!
let db = Firestore.firestore()
var dreamDictionary: [DreamDictionary] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.dataSource = self
tableView.delegate = self
title = K.Dictionary.appName
tableView.register(UINib(nibName: K.Dictionary.cellNibName, bundle: nil), forCellReuseIdentifier:
K.Dictionary.cellIdentifier)
loadDictionaryList()
}
func loadDictionaryList() {
db.collection(K.Fstore1.collectionName)
.order(by: K.Fstore1.date)
.addSnapshotListener{ (QuerySnapshot, error) in
self.dreamDictionary = []
if let e = error {
print("There was an issue retrieving data from Firestore. \(e)")
} else {
if let snapshotDocuments = QuerySnapshot?.documents {
for doc in snapshotDocuments {
//print(doc.data())
let data = doc.data()
if let symbolRetrieved = data[K.Fstore1.symbol] as? String, let meaningRetrieved = data[K.Fstore1.meaning] as? String {
let newDictList = DreamDictionary(mysymbol: symbolRetrieved, mymeaning: meaningRetrieved)
self.dreamDictionary.append(newDictList)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
}
}
}
extension PersonalDreamDictionaryViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dreamDictionary.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let dictCell = tableView.dequeueReusableCell(withIdentifier: K.Dictionary.cellIdentifier, for: indexPath)
as! DictionaryCell
if let symbolInput = dictCell.DictSymbolTextfield.text, let meaningInput = dictCell.SymbolMeaningTextfield.text { db.collection(K.Fstore1.collectionName).addDocument(data: [
K.Fstore1.symbol: symbolInput,
K.Fstore1.meaning: meaningInput,
K.Fstore1.date: Date().timeIntervalSince1970
]) { (error) in
if let e = error {
print("There was an issue saving data to firesore, \(e)")
} else {
print("Successfully saved data.")
}
}
}
return dictCell
}
}
extension PersonalDreamDictionaryViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
print(indexPath.row)
}
}

Passing access from tableViewController to another view controller

I have spent a fair bit of time on this and still can't seem to figure out what I'm doing wrong.
I would like to run the reloadData() function in my own function on another view controller than the tableViewController but I get the error Type 'HomeViewController' has no member 'reloadData'.
HomeViewController:
import UIKit
import CoreData
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var index = ""
var item : [ListItem] = [] //listName
var listName = [""]
override func viewDidLoad() {
super.viewDidLoad()
self.homeListsTableView.delegate = self
self.homeListsTableView.dataSource = self
homeListsTableView.reloadData()
//List Names
//List Items - Within a list Name
let listItem1 = ListItem()
listItem1.name = "" //Update so names are updated via append the ListItem Array
listItem1.location = ""
item.append(listItem1)
let listItem2 = ListItem()
listItem2.name = ""
listItem2.location = ""
item.append(listItem2)
}
#IBOutlet weak var homeListsTableView: UITableView!
#IBAction func templatesButton(_ sender: Any) {
tabBarController?.selectedIndex = 2
}
override func viewWillAppear(_ animated: Bool) {
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
if let coreDataListItems = try? context.fetch(ListName.fetchRequest()) as? [ListName] {
print(coreDataListItems)
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = listName[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// performSegue(withIdentifier: "goToItems", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! ListNameViewController
vc.homeListsTableViewVC = homeListsTableView
}
}
ListName View Controller:
import UIKit
import CoreData
class ListNameViewController: UIViewController, UITableViewDelegate {
// var listName = [""]
let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext
var homeListsTableViewVC = HomeViewController.self
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var listNameValue: UITextField!
#IBOutlet weak var locationOption: UITextField!
#IBOutlet weak var createButtonChange: UIButton!
#IBAction func createButton(_ sender: Any) {
let newList = ListName(context: context!)
newList.listName = listNameValue.text
// let location = locationOption.text!
//tabBarController?.selectedIndex = 0
//performSegue(withIdentifier: "home", sender: nil)
}
func saveList() {
do {
try context!.save()
} catch {
print("Error saving context \(error)")
}
homeListsTableViewVC.reloadData()
}
}
I'm trying to use the prepare for segue function to pass the homeListsTableView data to then use the reloadData() function. Could someone tell me what I'm doing wrong?
Thanks!
You can use delegate or closure to update your tableview.. here is pointers of how you can use closure in your classes to update view
class ListNameViewController: UIViewController, UITableViewDelegate {
var callback: (()->())?
//....
func saveList() {
do {
try context!.save()
} catch {
print("Error saving context \(error)")
}
callback?()
}
}
And while creating ListNameViewController
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! ListNameViewController
vc.callback = { [weak self] in
self?.homeListsTableView.reloadData()
}
}
}

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
}