I have a tableview that has a list of users in a directory that are loaded in from a firebase directory. My question is how can i put them into sections similarly to that of the contact app in the iPhone. I want each user to be displayed by their name under the appropriate sections.
here is the code I have:
my main view controller:
import UIKit
import Foundation
import Firebase
import FirebaseDatabase
class ViewController: UIViewController {
//MARK: - variables for the textfield search
#IBOutlet var field: UITextField!
var filteredTable = [String]()
//MARK: - Variables for the tableview data from Firebase
var table = [FacStaffInfo]()
var ref: DatabaseReference!
#IBOutlet weak var Tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//MARK: - setting the delegate for the test field for filter
field.delegate = self
//MARK: - This is all the functionality for the loading from Firebase to the TableView
ref = Database.database().reference().child("users")
ref.observe(DataEventType.value, with: {(snapshot) in
if snapshot.childrenCount > 0 {
self.table.removeAll()
for user in snapshot.children.allObjects as! [DataSnapshot] {
let object = user.value as? [String: AnyObject]
let title = object?["title"]
let name = object?["name"]
let email = object?["email"]
let phone = object?["phone"]
let office = object?["office"]
let bio = object?["bio"]
let user = FacStaffInfo(title: title as! String, name: name as! String, email: email as! String, phone: phone as! Int, office: office as! String, bio: bio as! String)
self.table.append(user)
self.Tableview.reloadData()
}
}
})
}
}
//MARK: - add the tableview functions
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//MARK: - adding functionality for textfield search
if !filteredTable.isEmpty {
return table.count
}
//MARK: - just returning the array from the database, keep if remove textfield crap
return table.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell") as! TableViewCell
let user: FacStaffInfo
user = table[indexPath.row]
cell.titleLabel?.text = user.title
cell.nameLabel?.text = user.name
cell.emailLabel?.text = user.email
cell.phoneLabel?.text = String(user.phone)
cell.officeLabel?.text = user.office
cell.bioLabel?.text = user.bio
//MARK: - testing using arrays to filter tableview data
// if !filteredTable.isEmpty {
// cell.textLabel?.text = filteredTable[indexPath.row]
// }
// else {
// cell.textLabel?.text = table.
// }
//
//
//
//
//
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetail", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = Tableview.indexPathForSelectedRow {
let destinationController = segue.destination as! InfoViewController
destinationController.FacStaffData = table[indexPath.row]
}
}
}
}
This is my data model
import Foundation
import Firebase
import FirebaseDatabase
class FacStaffInfo {
var title: String
var name: String
var email: String
var phone: Int
var office: String
var bio: String
init(title: String, name: String, email: String, phone: Int, office: String, bio: String) {
self.title = title;
self.name = name;
self.email = email;
self.phone = phone;
self.office = office;
self.bio = bio
}
}
This is my table view cell
import UIKit
import Firebase
import FirebaseDatabase
class TableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var phoneLabel: UILabel!
#IBOutlet weak var officeLabel: UILabel!
#IBOutlet weak var bioLabel: 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
}
}
Swift 5
Declare your class as follows:
class ViewController: UIViewController
{
// MARK: Outlets
#IBOutlet weak var Tableview: UITableView!
#IBOutlet weak var field: UITextField!
// MARK: Properties
var sectionNames: [String] = []
var users: [String: [FacStaffInfo]] = [:]
var ref: DatabaseReference!
// MARK: View Controller Life Cycle
override func viewDidLoad()
{
super.viewDidLoad()
getUsersFromFirebaseDB()
}
deinit
{
ref.removeAllObservers()
}
// MARK: Private Methods
private func usersFetched(_ usersData: [FacStaffInfo])
{
for user in usersData
{
guard let userNameFirstChar = user.name.first?.uppercased() else { continue }
if var usersForKey = users["\(userNameFirstChar)"]
{
usersForKey.append(user)
users["\(userNameFirstChar)"] = usersForKey
}
else
{
// no users are stored in dictionary for key userNameFirstChar
users["\(userNameFirstChar)"] = [user]
}
}
// sort dictionary keys and set it in sectionNames
sectionNames = users.map { $0.key }.sorted()
}
private func getUsersFromFirebaseDB()
{
ref = Database.database().reference().child("users")
ref.observe(DataEventType.value, with: { [weak self] (snapshot) in
guard snapshot.childrenCount > 0 else { return }
var users: [FacStaffInfo] = []
for user in snapshot.children.allObjects as! [DataSnapshot]
{
let object = user.value as? [String: AnyObject]
let title = object?["title"]
let name = object?["name"]
let email = object?["email"]
let phone = object?["phone"]
let office = object?["office"]
let bio = object?["bio"]
let user = FacStaffInfo(title: title as! String, name: name as! String, email: email as! String, phone: phone as! Int, office: office as! String, bio: bio as! String)
users.append(user)
}
self?.usersFetched(users)
self?.Tableview.reloadData()
})
}
// MARK: Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "showDetail"
{
if let indexPath = Tableview.indexPathForSelectedRow
{
let destinationController = segue.destination as! InfoViewController
let char = sectionNames[indexPath.section]
let user = users[char]![indexPath.row]
destinationController.FacStaffData = user
}
}
}
}
Also, add the following extension:
extension ViewController: UITableViewDataSource, UITableViewDelegate
{
func numberOfSections(in tableView: UITableView) -> Int
{
sectionNames.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
sectionNames[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let char = sectionNames[section]
return users[char]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell") as! TableViewCell
let char = sectionNames[indexPath.section]
let user = users[char]![indexPath.row]
cell.nameLabel?.text = user.name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
performSegue(withIdentifier: "showDetail", sender: self)
tableView.deselectRow(at: indexPath, animated: true)
}
}
Output
Related
I have a weird problem.
I have two TableViews one for showing Projects and one for showing all Team Members. With both TableViews I have the same bug.
When a user clicks on a Project/ Team Member I want to show the Details for it.
The weird thing is, when running the app and I select a Project/ Team Member for the first time, nothing is happening. When I then select another one, it shows me the details of the previous selected one.
I hope someone can help me with that.
Also a weird thing is, the entry "Sarra Fezzani" was deleted from the Firebase Database and the app was clean build, but it still shows it several times...
Since both codes are pretty similiar I will only post the Code for the ProjetTableViewController without the other files.
//
// TeamViewController.swift
// ProLabArtv2
//
import UIKit
class TeamViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var memberTableView: UITableView!
#IBOutlet weak var addTeamMember: UIButton!
var members = [TeamMember]()
var textToBeSent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
setUpElements()
UserService.members(for: User.current) { (members) in
self.members = members
self.memberTableView.reloadData()
}
}
// MARK: - Element Style
func setUpElements() {
// Mark: Style the elements
Utilities.addShadowtoButton(addTeamMember)
}
func configureTableView() {
// remove separators for empty cells
memberTableView.tableFooterView = UIView()
// remove separators from cells
memberTableView.separatorStyle = .none
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMemberDetails" {
let destVC = segue.destination as! TeamMemberDetailsViewController
destVC.member = sender as? TeamMember
}
}
}
// MARK: - UITableViewDataSource
extension TeamViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let member = members[indexPath.row]
let cell = memberTableView.cellForRow(at: indexPath)
print(members)
performSegue(withIdentifier: "toMemberDetails", sender: member)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return members.count
}
// func numberOfSections(in tableView: UITableView) -> Int {
// return members.count
// }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let member = members[indexPath.row]
let cell = memberTableView.dequeueReusableCell(withIdentifier: "TeamMemberCell") as! TeamMemberCell
cell.jobLabel.text = members[indexPath.row].memberJob
cell.nameLabel.text = members[indexPath.row].memberName
return cell
}
}
// MARK: - UITableViewDelegate
extension TeamViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
import UIKit
class TeamMemberCell: UITableViewCell {
// MARK: - Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
static let height: CGFloat = 78
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
}
}
import Foundation
import UIKit
import FirebaseDatabase.FIRDataSnapshot
class TeamMember {
// Next let's add properties to store all the additional information we need. Add the following to your post class.
var key: String?
let memberName: String
let memberJob: String
let memberLanguage: String
let memberPrice: String
let memberSpecification: String
// You'll get some compiler errors for not having any initializers or default values for certain properties. Let's go ahead and fix that:
init(memberName: String, memberJob: String, memberLanguage: String, memberPrice: String, memberSpecification: String) {
self.memberName = memberName
self.memberJob = memberJob
self.memberLanguage = memberLanguage
self.memberPrice = memberPrice
self.memberSpecification = memberSpecification
}
var dictValue: [String : Any] {
return ["memberName" : memberName,
"memberJob" : memberJob,
"memberLanguage" : memberLanguage,
"memberPrice" : memberPrice,
"memberSpecification" : memberSpecification]
}
init?(snapshot: DataSnapshot) {
guard let dict = snapshot.value as? [String : Any],
let memberName = dict["memberName"] as? String,
let memberJob = dict["memberJob"] as? String,
let memberLanguage = dict["memberLanguage"] as? String,
let memberPrice = dict["memberPrice"] as? String,
let memberSpecification = dict["memberSpecification"] as? String
else { return nil }
self.key = snapshot.key
self.memberName = memberName
self.memberJob = memberJob
self.memberLanguage = memberLanguage
self.memberPrice = memberPrice
self.memberSpecification = memberSpecification
}
}
import Foundation
import FirebaseAuth.FIRUser
import FirebaseDatabase
import FirebaseUI
import FirebaseAuth
struct UserService {
static func members(for user: User, completion: #escaping ([TeamMember]) -> Void) {
let ref = Database.database().reference().child("team").child(user.uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let snapshot = snapshot.children.allObjects as? [DataSnapshot] else {
return completion([])
}
let members = snapshot.reversed().compactMap(TeamMember.init)
completion(members)
})
}
}
//
// TeamMemberDetailsViewController.swift
// ProLabArtv2
//
// Created by Manu on 09.06.20.
// Copyright © 2020 Manuel Knott. All rights reserved.
//
import UIKit
import FirebaseDatabase
import FirebaseAuth
import FirebaseStorage
class TeamMemberDetailsViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
#IBOutlet weak var specificationLabel: UILabel!
#IBOutlet weak var languageLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var newScoreButton: UIButton!
#IBOutlet weak var projectsPartButton: UIButton!
var member: TeamMember?
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
func setUI() {
nameLabel.text = member?.memberName
jobLabel.text = member?.memberJob
specificationLabel.text = member?.memberSpecification
languageLabel.text = member?.memberLanguage
priceLabel.text = member?.memberPrice
// scoreLabel.text = member?.
}
}
And that's the one for the ProjectViewController, where I am using a switch statement...
// HomeViewController.swift
// ProLabArtv2
//
//
import UIKit
import Kingfisher
import Foundation
import FirebaseStorage
import FirebaseDatabase
class HomeViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var addProject: UIButton!
var posts = [Post]()
var textToBeSent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
UserService.posts(for: User.current) { (posts) in
self.posts = posts
self.tableView.reloadData()
}
Utilities.addShadowtoButton(addProject)
}
func configureTableView() {
// remove separators for empty cells
tableView.tableFooterView = UIView()
// remove separators from cells
tableView.separatorStyle = .none
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetails" {
let destVC = segue.destination as! ShowProjectDetailsViewController
destVC.post = sender as? Post
}
}
}
// MARK: - UITableViewDataSource
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let post = posts[indexPath.row]
performSegue(withIdentifier: "toDetails", sender: post)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func numberOfSections(in tableView: UITableView) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.section]
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "PostImageCell") as! PostImageCell
let imageURL = URL(string: post.imageURL)
cell.postImageView.kf.setImage(with: imageURL)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "PostSubCell") as! PostSubCell
cell.projectName.text = post.projectTitle
return cell
default:
fatalError("Error: unexpected indexPath.")
}
}
}
// MARK: - UITableViewDelegate
extension HomeViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
let post = posts[indexPath.section]
return post.imageHeight
case 1:
return PostSubCell.height
default:
fatalError()
}
}
}
Hopefully someone can help me :)
This is one of those errors we've all made at some point, usually by not reading the autocomplete carefully.
Your code is
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
You've used the didDeselectRowAt rathert than didSelectRowAt method. Which means that it runs it when that row loses focus (which will be when you click on another row).
You need
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
You are using the wrong delegate method. Perform the segue on selecting rather than deselecting a cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let post = posts[indexPath.row]
performSegue(withIdentifier: "toDetails", sender: post)
}
Ive been stuck trying to pass data from the FoodEatenController(FEC) Footer to the TotalCaloriesController. The code that I have now it shows NOTHING in the calorieLbl of the TotalCalorieController(TCC).
The delegate that ive been using to pass the data from the FEC to the TCC does not pass the text/string data that is in the FoodFooter calorieTotallbl to the TEC calorieLbl
the data that populates the cells of the FEC is retrieved from Cloud Firestore and passed in from anotherView Controller (FoodPickerController)
import UIKit
class FoodEatenController: UIViewController{
var selectedFood: FoodList! // allows data to be passed into the VC
// allows data to be sepearted into sections
var foodItems: [FoodItem] = []
var groupedFoodItems: [String: [FoodItem]] = [:]
var dateSectionTitle: [String] = []
#IBOutlet weak var tableView: UITableView!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? TotalCalorieController {
}
}
}
extension FoodEatenController: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return dateSectionTitle.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let date = dateSectionTitle[section]
return groupedFoodItems[date]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foodCell = tableView.dequeueReusableCell(withIdentifier: "FoodCell") as! FoodCell
let date = dateSectionTitle[indexPath.section]
let foodItemsToDisplay = groupedFoodItems[date]![indexPath.row]
foodCell.configure(withCartItems: fooditemsToDisplay.foodList)
return foodCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let foodHeader = tableView.dequeueReusableCell(withIdentifier: "FoodHeader") as! FoodHeader
let headerTitle = dateSectionTitle[section]
foodHeader.dateLbl.text = "Date: \(headerTitle)"
return foodHeader
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let foodFooter = tableView.dequeueReusableCell(withIdentifier: "FoodFooter") as! FoodFooter
let date = dateSectionTitle[section]
let arrAllItems = groupedFoodItems[date]!
var total: Float = 0
for item in arrAllItems {
let eaten = item.productList
let selectedMeal = item.foodList.selectedOption
if selectedMeal == 1 {
total = total + (Float(eaten!.calorie))
}
}
foodFooter.calorieTotal.text = String(subtotal!)
foodFooter.delegate = self
return foodFooter
}
}
extension FoodEatenController: EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
let popUp = self.storyboard?.instantiateViewController(withIdentifier: "AdditionalCostsVC") as! TotalCalorieController
popUp.calorieLbl.text = info
}
}
import UIKit
protocol EatenFoodDelegate: class {
func onTouchCaloireInfo(info: String)
}
class FoodFooter: UITableViewCell {
weak var delegate: EatenFoodDelegate? = nil
#IBOutlet weak var calorieTotal: UILabel!
#IBOutlet weak var totalInfoBtn: UIButton!
#IBAction func totalOnClicked(_ sender: AnyObject) {
self.delegate?. onTouchCaloireInfo(info: calorieTotal.text!)
}
}
class TotalCalorieController: UIViewController, EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
calorieLbl.text = info
}
#IBOutlet weak var calorieLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func returnButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
print("Close Taxes and Fees")
}
}
Add the following line at the end of the func onTouchCaloireInfo(info:)
self.present(popUp, animated: true, completion: nil)
If you would like to be sure that the function onTouchCaloireInfo(info:) gets called, just add the following line:
debugPrint("onTouchCaloireInfo")
And check, if it prints the given string in the console of the Xcode
extension FoodEatenController: EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
debugPrint("onTouchCaloireInfo")
let popUp = self.storyboard?.instantiateViewController(withIdentifier: "AdditionalCostsVC") as! TotalCalorieController
self.present(popUp, animated: true) {
popUp.calorieLbl.text = info
}
}
}
So, I have a UIViewController(PledgeViewController) with a TableView. When the user clicks on a UIButton(plusBtn) in the UITableViewCell(PledgeTableViewCell) of the TableView, I want to perform a write to my firebase database. But to get the exact path, I need a String(getID) from the PledgeViewController class which is received with a segue from the previous ViewController. With the MVC format that I'm using, how do I access values in the PledgeViewController to write to the database from the PledgeTableViewCell?
My PledgeViewController.swift:
import UIKit
import Foundation
import FirebaseDatabase
import Firebase
class PledgeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
var getID: String!
#IBOutlet weak var pledgeAmtLabel: UILabel!
#IBOutlet weak var RewardChooseTable: UITableView!
#IBAction func pledgeBtn(_ sender: Any) {
//get the text from the label and run all the checks to see if the tickets are available
}
let RewardRef = Database.database().reference().child("Rewards")
var rewards = [Rewards]()
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rewards.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TakePledgeCell", for: indexPath) as! PledgeTableViewCell
let reward = rewards[indexPath.row]
cell.reward = reward
return cell
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
RewardRef.child(getID).observe(.value, with: { (snapshot) in
self.rewards.removeAll()
for child in snapshot.children {
let childSnapshot = child as! DataSnapshot
let reward = Rewards(snapshot: childSnapshot)
self.rewards.insert(reward, at: 0)
}
self.RewardChooseTable.reloadData()
})
}
override func viewDidLoad() {
super.viewDidLoad()
print("The id received from the SingleViewControl is:" + getID)
}
}
My PledgeTableViewCell.swift:
import UIKit
import Firebase
import FirebaseDatabase
class PledgeTableViewCell: UITableViewCell {
#IBOutlet weak var rewardAmtLabel: UILabel!
#IBOutlet weak var ticketClasslabel: UILabel!
#IBOutlet weak var ticketDescLabel: UILabel!
#IBOutlet weak var ticketCountLabel: UILabel!
#IBOutlet weak var plusBtn: UIButton!
#IBOutlet weak var minusBtn: UIButton!
var ref: DatabaseReference!
var artcallid: Int!
#IBAction func minusBtn(_ sender: Any) {
}
var reward: Rewards! {
didSet {
rewardAmtLabel.text = "Rs. " + String(reward.rewardAmt)
ticketClasslabel.text = reward.reward_class_name
ticketDescLabel.text = reward.reward_desc
print(reward.reward_class_name + " is one of the rewards")
}
}
#IBAction func plusBtn(_ sender: AnyObject) {
}
}
Rewards.swift:
import Foundation
import Firebase
import FirebaseDatabase
class Rewards {
let ref: DatabaseReference!
// let countRef: DatabaseReference!
var rewardAmt: Int!
var rewardsLeft: Int!
var reward_class_name: String = ""
var reward_amt: String = ""
var reward_desc: String = ""
var rewardID: String = ""
var tickUpCount = 0
var tickDownCount = 0
init(text: String) {
ref = Database.database().reference().child("Fund").childByAutoId()
// countRef = Database.database().reference().child("Testing").childByAutoId()
}
init(snapshot: DataSnapshot)
{
ref = snapshot.ref
if let value = snapshot.value as? [String : Any] {
rewardAmt = value["reward_ticket_amount"] as! Int
reward_class_name = value["reward_ticket_amount_class_name"] as! String
reward_amt = value["reward_ticket_amount_txt"] as! String
reward_desc = value["reward_ticket_class_desc"] as! String
rewardsLeft = value["rewards_left"] as! Int
rewardID = snapshot.key
}
}
}
extension Rewards{
func countUp(){
tickUpCount += 1
ref.child("uppingTicket").setValue(tickUpCount)
}
}
You can try with closure
class PledgeTableViewCell: UITableViewCell {
//Define a closure
var closure:(() -> Void)? = nil
#IBAction func plusBtn(_ sender: AnyObject) {
// Do you stuff
closure?()
}
}
class PledgeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TakePledgeCell", for: indexPath) as! PledgeTableViewCell
let reward = rewards[indexPath.row]
cell.reward = reward
cell.closure = {
// You will get the callback in this block
// You can define the parameterized closure to return the value
}
return cell
}
You can try to add a new var
class PledgeTableViewCell: UITableViewCell {
var currentID = ""
}
and set it in cellForRowAt
cell.currentID = getID
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
So, I have a ViewController(PledgeViewController) with a UITableView and another file called PledgeTableViewCell.swift which is a UITableCell file. When someone clicks a button(plsBtn) in the PledgeTableViewCell.swift, I have set up a closure which feeds back into the PledgeViewController and I handle my operations from there. What I want to do now is this:
When someone clicks the plsBtn in the PledgeTableViewCell, I'm handling that action in the PledgeViewController. But I want to read the value of a label in the TableViewCell at that indexPath and send it to the PledgeViewController for further calculations. Can I do this with the closure itself or is there another method? Thanks!
PledgeTableViewCell.swift:
import UIKit
import Firebase
import FirebaseDatabase
class PledgeTableViewCell: UITableViewCell {
var plusBtnAction: ((Any) -> Void)?
var minusBtnAction: ((Any) -> Void)?
#IBOutlet weak var rewardAmtLabel: UILabel!
#IBOutlet weak var ticketClasslabel: UILabel!
#IBOutlet weak var ticketDescLabel: UILabel!
#IBOutlet weak var ticketCountLabel: UILabel!
#IBOutlet weak var plusBtn: UIButton!
#IBOutlet weak var minusBtn: UIButton!
var ref: DatabaseReference!
var currentID = ""
var ticket_count: Int = 0
let userID = Auth.auth().currentUser!.uid
#IBAction func minusBtn(_ sender: Any) {
if var tickCount = Int(ticketCountLabel.text!) {
if(tickCount > 0)
{
tickCount -= 1
ticketCountLabel.text = String(tickCount)
}
}
self.minusBtnAction?(sender)
}
#IBAction func plusBtn(_ sender: AnyObject) {
if var tickCount = Int(ticketCountLabel.text!) {
//I WANT TO SEND THIS 'TICKCOUNT' TO THE PLEDGEVIEWCONTROLLER
tickCount += 1
ticketCountLabel.text = String(tickCount)
}
self.plusBtnAction?(sender)
}
}
PledgeViewController.swift:
import UIKit
import Foundation
import FirebaseDatabase
import Firebase
class PledgeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
var getID: String!
var rewards = [Rewards]()
var ticket_count: Int = 0
var ref: DatabaseReference!
let userID = Auth.auth().currentUser!.uid
var rewardID: String!
#IBOutlet weak var pledgeAmtLabel: UILabel!
#IBOutlet weak var RewardChooseTable: UITableView!
#IBAction func pledgeBtn(_ sender: Any) {
//get the text from the label and run all the checks to see if the tickets are available
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
/* myIndex = indexPath.row
finalId = idTable[myIndex]
let story = stories[indexPath.row]
ArtcallID = story.id
performSegue(withIdentifier: "singleArtcall", sender: self)
*/
let reward = rewards[indexPath.row]
let id = reward.rewardID
reward.countUp()
print("The reward that was touched is: " + id )
print("One of the buttons were touched")
}
let RewardRef = Database.database().reference().child("Rewards")
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rewards.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TakePledgeCell", for: indexPath) as! PledgeTableViewCell
let reward = rewards[indexPath.row]
cell.reward = reward
cell.currentID = getID
rewardID = reward.rewardID
cell.plusBtnAction = { sender in
let reward = self.rewards[indexPath.row]
cell.reward = reward
let local_id = reward.rewardID
self.ref=Database.database().reference().child("Fund_Project_Request").child(self.getID).child(self.userID).child(local_id).child("Ticket_count")
self.ref.observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
if snapshot.value is NSNull{
self.ticket_count = 0
self.ticket_count += 1
self.ref.setValue(self.ticket_count)
}
else{
self.ticket_count = snapshot.value as! Int
self.ticket_count += 1
self.ref.setValue(self.ticket_count)
}
}) { (error) in
print(error.localizedDescription)
}
Database.database().reference().child("Rewards").child(self.getID).child(local_id).child("reward_ticket_amount").observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let reward_amt = snapshot.value as! Int
self.pledgeAmtLabel.text = String(reward_amt)
}) { (error) in
print(error.localizedDescription)
}
// Do whatever you want from your button here.
}
cell.minusBtnAction = { sender in
let reward = self.rewards[indexPath.row]
cell.reward = reward
let local_id = reward.rewardID
self.ref=Database.database().reference().child("Fund_Project_Request").child(self.getID).child(self.userID).child(local_id).child("Ticket_count")
self.ref.observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
if snapshot.value is NSNull{
}
else{
self.ticket_count = snapshot.value as! Int
if(self.ticket_count != 0)
{
self.ticket_count -= 1
self.ref.setValue(self.ticket_count)
}
}
}) { (error) in
print(error.localizedDescription)
}
}
return cell
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
RewardRef.child(getID).observe(.value, with: { (snapshot) in
self.rewards.removeAll()
for child in snapshot.children {
let childSnapshot = child as! DataSnapshot
let reward = Rewards(snapshot: childSnapshot)
self.rewards.insert(reward, at: 0)
}
self.RewardChooseTable.reloadData()
})
}
override func viewDidLoad() {
super.viewDidLoad()
print("The id received from the SingleViewControl is:" + getID)
}
}
You can pass the label value in the closure itself along with sender.
class PledgeTableViewCell: UITableViewCell {
var plusBtnAction: ((String) -> Void)?
var minusBtnAction: ((String) -> Void)?
#IBAction func minusBtn(_ sender: Any) {
if var tickCount = Int(ticketCountLabel.text!) {
if(tickCount > 0)
{
tickCount -= 1
ticketCountLabel.text = String(tickCount)
}
self.minusBtnAction?(tickCount)
}
}
#IBAction func plusBtn(_ sender: AnyObject) {
if var tickCount = Int(ticketCountLabel.text!) {
//I WANT TO SEND THIS 'TICKCOUNT' TO THE PLEDGEVIEWCONTROLLER
tickCount += 1
ticketCountLabel.text = String(tickCount)
self.plusBtnAction?(ticketCount)
}
}
}
in cellForRow: method in PledgeViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TakePledgeCell", for: indexPath) as! PledgeTableViewCell
.....
cell.plusBtnAction = { labelText in
//handle labelText here
}
}
So im populating a table View from firebase database. I am able to add and remove check marks. But i can't seem to figure out how to save it. Since the tableView reloads the data every time the view appears.
here is my view controller
import UIKit
import FirebaseDatabase
import Firebase
class guestListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var guestListTableView: UITableView!
var guestListDBRef : DatabaseReference!
var guestListText = [AdminTextModel]()
var keyArray : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
guestListDBRef = Database.database().reference().child("RSVP")
guestListDBRef.queryOrdered(byChild: "name").observe(DataEventType.value, with: {(snapshot) in
if snapshot.childrenCount > 0 {
for guestListLabel in snapshot.children.allObjects as! [DataSnapshot] {
let guestListTextObject = guestListLabel.value as? [String: AnyObject]
let name = guestListTextObject?["name"]
let date = guestListTextObject?["date"]
let guestListTextLabels = AdminTextModel(name: name as! String?, date: date as! String?)
self.guestListText.append(guestListTextLabels)
self.guestListTableView.rowHeight = 45
self.guestListTableView.reloadData()
self.getKeys()
}
}
})
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return guestListText.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let guestListTextCell = tableView.dequeueReusableCell(withIdentifier: "guestList") as! guestListTableViewCell
let text: AdminTextModel
text = guestListText[indexPath.row]
guestListTextCell.guestListNameLabel.text = text.name
guestListTextCell.guestListDateLabel.text = text.date
return guestListTextCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
My AdminTextModel
import Foundation
class AdminTextModel {
var name: String?
var date: String?
init(name: String?, date: String?) {
self.name = name
self.date = date
}
}
And my TableViewCell
import UIKit
class guestListTableViewCell: UITableViewCell {
#IBOutlet weak var guestListDateLabel: UILabel!
#IBOutlet weak var guestListNameLabel: 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
}
}
Let me know if you have any input!
enter image description here
enter image description here
enter image description hereng
Change your model to this
class AdminTextModel {
var name: String?
var date: String?
var isChecked: Bool?
init(name: String?, date: String?, isChecked: Bool?) {
self.name = name
self.date = date
self.isChecked = isChecked
}
}
The isChecked property should also be saved in your firebase database
Now fetch the data and set the checkmark to true or false based on the isChecked property.
This will retain the checkmark even after reloading the screen
Thank you!, I went ahead and implemented that iParesh, but i think my issue lies here. Since im using childByAutoID.
let onlinesRef = Database.database().reference().child("RSVP").child("yourchild name")
As per Moaz Khan change model class and also need to change in cellForRowAt with below code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let guestListTextCell = tableView.dequeueReusableCell(withIdentifier: "guestList") as! guestListTableViewCell
let text: AdminTextModel
text = guestListText[indexPath.row]
guestListTextCell.guestListNameLabel.text = text.name
guestListTextCell.guestListDateLabel.text = text.date
if text.isChecked {
cell.accessoryType = .checkmark
}else {
cell.accessoryType = .none
}
return guestListTextCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let isChecked = !self.guestListText[indexPath.row].isChecked
let key = self.guestListText[indexPath.row].key
Checkedservice.checkuncheck(key: key, isChecked: isChecked) { (seccess) in
guard seccess else { return }
self.guestListText[indexPath.section].isChecked = isChecked
self.tableView.reloadRows(at: [indexPath], with: .none)
}
}
Check mark service for firebase
struct Checkedservice {
static func checkuncheck(key: String, isChecked: Bool, success: #escaping (Bool) -> Void) {
let onlinesRef = Database.database().reference().child("RSVP").child(key).child("isChecked")
onlinesRef.setValue(isChecked) {(error, _ ) in
if let error = error {
assertionFailure(error.localizedDescription)
success(false)
}
success(true)
}
}
}
Update model class
class AdminTextModel {
var key: String?
var name: String?
var date: String?
var isChecked: Bool?
init(key: String?, name: String?, date: String?, isChecked: Bool?) {
self.key = key
self.name = name
self.date = date
self.isChecked = isChecked
}
}