My first Screen
Then I go on to login screen by clicking "Sign In" button.
My Login Screen
Next I go on to the screen with the table view... This is how it looks when I successfully login:
Table View Screen
Next I click on the add resident icon(the small icon with the person and the plus sign) and I get this page in which I can register a resident.
Register Resident Screen
Next, what should happen is, when I click the add button, it should "successfully save" my core data and it should automatically dismiss this view and got back to the "Table View Screen" (Previous Picture). But it doesn't! When it goes to the Table View Screen, it should register the new resident with the name "Bob" and the Age "45" saved in my core data successfully. Please help me fix these 2 problems...
This is the view controller in which my data is saved using core data. I get "successfully saved" when I click the "Add" button.
// ResidentViewController.swift
// 77 Safety Updater
//
// Created by Tejas Ravishankar on 17/04/20.
// Copyright © 2020 Tejas Ravishankar. All rights reserved.
//
//MARK:- Import Modules
import UIKit
import CoreData
let appDelegate = UIApplication.shared.delegate as? AppDelegate
class ResidentViewController: UIViewController {
//MARK:- Variables
var residentCount : Int = 0
var travelSwitchIsOn : Bool = false
var movedInSwitchIsOn : Bool = false
var stateColor : UIColor = .systemGreen
var name : String = ""
var age : Int = 0
var type : Int = 0
var risk : String = ""
//MARK:- IB Outlets
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var riskLabel: UILabel!
#IBOutlet weak var ageTextField: UITextField!
#IBOutlet weak var workingSwitch: UISwitch!
#IBOutlet weak var movedInSwitch: UISwitch!
#IBOutlet weak var movedInLabel: UILabel!
#IBOutlet weak var yesLabel: UILabel!
#IBOutlet weak var noLabel: UILabel!
//MARK:- Add Button Action
#IBAction func addButtonPressed(_ sender: UIButton)
{
residentCount += 1
let ageText = ageTextField.text
if ageText!.count >= 4
{
ageTextField.text = ""
ageTextField.placeholder = "Invalid Age!"
}
name = nameTextField.text!
age = Int(ageText!)!
travelSwitchIsOn = workingSwitch.isOn
movedInSwitchIsOn = movedInSwitch.isOn
if movedInSwitchIsOn == true || travelSwitchIsOn == true
{
risk = "Medium"
}
else if movedInSwitchIsOn == true && travelSwitchIsOn == true
{
risk = "High"
}
else
{
risk = "Low"
}
if age <= 4
{
stateColor = .systemRed
}
if age <= 20
{
stateColor = .systemGreen
}
else if age >= 55 && age <= 90
{
stateColor = .systemRed
}
else if age > 90
{
stateColor = .systemPurple
}
if nameTextField.text != "" && ageTextField.text != ""
{
saveData { (complete) in
if complete
{
self.dismiss(animated: true, completion: nil)
}
}
}
}
//MARK:- Core Data Save Function
func saveData(completion:(_ finished:Bool) -> ())
{
guard let managedContext = appDelegate?.persistentContainer.viewContext
else
{
return
}
let data = UserData(context: managedContext)
data.name = name
data.age = Int32(age)
data.risk = risk
do {
try managedContext.save()
print("Successfully Saved!")
completion(true)
}
catch {
debugPrint("Save Failed: \(error.localizedDescription)")
}
}
//MARK:- Resident Type Action
#IBAction func residentTypeChanged(_ sender: UISegmentedControl)
{
let type = sender.selectedSegmentIndex
if type == 0
{
movedInSwitch.isHidden = true
movedInLabel.isHidden = true
yesLabel.isHidden = true
noLabel.isHidden = true
}
if type == 1
{
movedInSwitch.isHidden = false
movedInLabel.isHidden = false
yesLabel.isHidden = false
noLabel.isHidden = false
}
}
//MARK:- When App Screen Loads Up
override func viewDidLoad()
{
super.viewDidLoad()
movedInSwitch.isHidden = true
movedInLabel.isHidden = true
riskLabel.text = ""
ageTextField.delegate = self
yesLabel.isHidden = true
noLabel.isHidden = true
}
}
extension ResidentViewController : UITextFieldDelegate
{
#IBAction func ageTextField(_ sender: UITextField)
{
let age = Int(ageTextField.text!)
if age! <= 4
{
riskLabel.textColor = UIColor.systemGreen
stateColor = .systemRed
riskLabel.text = "High Risk Host!"
}
if age! <= 20
{
riskLabel.textColor = UIColor.systemGreen
stateColor = .systemGreen
riskLabel.text = "Low Risk Host!"
}
else if age! >= 55 && age! <= 90
{
riskLabel.textColor = UIColor.systemRed
stateColor = .systemRed
riskLabel.text = "High Risk Host!"
}
else if age! > 90
{
riskLabel.textColor = UIColor.systemPurple
stateColor = .systemPurple
riskLabel.text = "Very High Risk Host!"
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
ageTextField.endEditing(true)
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if ageTextField.text != ""
{
return true
}
else
{
textField.placeholder = "Type Something!"
return false
}
}
}
This is the table view controller which contains the configuration of the cell and the table! I have also fetched the data in this view controller. In the output: I get "successfully fetched!" Ignore the login view controller.swift as it just contains my authentication using user defaults... There are no parts of CoreData in that file...
//
// StatisticsViewController.swift
// 77 Safety Updater
//
// Created by Tejas Ravishankar on 17/04/20.
// Copyright © 2020 Tejas Ravishankar. All rights reserved.
//
//MARK:- Import Modules
import UIKit
import CoreData
class StatisticsViewController: UIViewController
{
var details : [UserData] = []
#IBOutlet weak var informationTableView: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
informationTableView.delegate = self
informationTableView.dataSource = self
informationTableView.isHidden = false
informationTableView.register(UINib(nibName: "InformationTableViewCell", bundle: nil), forCellReuseIdentifier: "informationCell")
}
func fetchData(completion:(_ complete:Bool) -> ())
{
guard let managedContext = appDelegate?.persistentContainer.viewContext
else
{
return
}
let fetchRequest = NSFetchRequest<UserData>(entityName: "UserData")
do {
try managedContext.fetch(fetchRequest) as![UserData]
print("Successfully Fetched!")
completion(true)
}
catch
{
debugPrint("Failed To Fetch: \(error.localizedDescription)")
completion(false)
}
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
self.fetchData { (complete) in
if complete
{
if details.count >= 1
{
informationTableView.isHidden = true
}
else
{
informationTableView.isHidden = false
}
}
}
}
}
extension StatisticsViewController : UITableViewDelegate,UITableViewDataSource
{
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
details.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = informationTableView.dequeueReusableCell(withIdentifier: "informationCell") as! InformationTableViewCell
let userDetail = details[indexPath.row]
cell.configureCell(userDetail)
return cell
}
}
This is my table view cell cocoa touch class in which I configure the data stored in the cells.
//
// InformationTableViewCell.swift
// 77 Safety Updater
//
// Created by Tejas Ravishankar on 26/04/20.
// Copyright © 2020 Tejas Ravishankar. All rights reserved.
//
import UIKit
import CoreData
class InformationTableViewCell: UITableViewCell
{
#IBOutlet weak var ageLabel: UILabel!
#IBOutlet weak var nameLabel: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
func configureCell(_ detail : UserData)
{
self.nameLabel.text = detail.name
self.ageLabel.text = String(describing: detail.age)
}
}
Thanks A Lot!!!
Related
I have a problem with passing the data
To make it clear, I will explain the idea of what I worked on, and what is the problem.
The idea is in the first view controller the user will enter the title and description and then chooses from the options of the pop-up button, the options are (exchange, borrow, donation, sell). The data entered will be saved in the option chosen by the user. then the data will be displayed in the second view controller in the table view. If the user chooses the exchange option and enters the data, his data will be displayed in the table view in the exchange (index 0) and this works for me the data is displayed in the table view in the correct form as I want.
The problem I am experiencing is when I pass the data to the other view controller.
When the user clicks on any cell, it will pass the same data regardless of the difference in the index. If the user chooses the borrow (index 1) and clicks any cell, it'll display the exchange (index 0) data. No matter what indexes you choose and the cell you click on it will pass the same data!!!!!
first view controller
here I'm entering the data
it's shown in the table view in the right index of the segment no problem with that
after I click it pass the right data
look here if I change the index and click to any cell it will pass the same data!!
look here if I change the index and click to any cell it will pass the same data!!
Here's my code for the first vc
import UIKit
import FirebaseFirestore
class ViewController4: UIViewController {
#IBOutlet weak var mssglabel: UILabel!
#IBOutlet weak var selectservice: UIButton!
#IBOutlet weak var titleTextField: UITextField!
#IBOutlet weak var descriptionTextField: UITextView!
#IBOutlet weak var custombtun: UIButton!
let db = Firestore.firestore()
var chooseOption = ""
override func viewDidLoad() {
super.viewDidLoad()
setpopupbutn()
selectservice.layer.cornerRadius = 25
descriptionTextField.layer.cornerRadius = 25
custombtun.layer.cornerRadius = 25
}
#IBAction func containbutn(_ sender: Any) {
let vc = (storyboard?.instantiateViewController(withIdentifier: "vc3"))!
navigationController?.pushViewController(vc, animated: true)
spcificOption()
}
func saveDataDonation() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text{
// Save Data to Database
db.collection("userDonationDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle)
}
} // end of closure
}
}
func saveDataSale() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text{
// Save Data to Database
db.collection("userSaleDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func saveDataExchange() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text {
// Save Data to Database
db.collection("userExchangeDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func saveDataBorrow() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text {
// Save Data to Database
db.collection("userBorrowDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func setpopupbutn () {
let option = {( ACTION : UIAction ) in
self.chooseOption = ACTION.title
print("حفظ الداتا في ",self.chooseOption)}
selectservice.menu = UIMenu (children : [
UIAction (title : "تبرع" , state: .on , handler: option),
UIAction (title : "بيع" , handler: option),
UIAction (title : "تبادل" , handler: option),
UIAction (title : "إستعارة" , handler: option),
])
saveDataDonation()
selectservice.showsMenuAsPrimaryAction = true
selectservice.changesSelectionAsPrimaryAction = true
}
func spcificOption() {
if chooseOption == ("تبرع") {
saveDataDonation()
} else if chooseOption == ("بيع") {
saveDataSale()
} else if chooseOption == ("تبادل") {
saveDataExchange()
} else if chooseOption == ("إستعارة") {
saveDataBorrow()
}
}
}
and this is the second vc (Table view)
import UIKit
import FirebaseFirestore
import Firebase
class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {
let db = Firestore.firestore()
var exchange : [exchange] = []
var borrow : [borrow] = []
var donation : [donation] = []
var sale : [sale] = []
#IBOutlet weak var segmentOutlet: UISegmentedControl!
#IBOutlet weak var userDataTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
userDataTableView.dataSource = self
userDataTableView.delegate = self
getDataDonation()
getDataSale()
getDataExchange()
getDataBorrow()
userDataTableView.reloadData()
}
#IBAction func serviceSeg(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
getDataExchange()
}
else if sender.selectedSegmentIndex == 1 {
getDataBorrow()
}
else if sender.selectedSegmentIndex == 2 {
getDataDonation()
}
else if sender.selectedSegmentIndex == 3 {
getDataSale()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentOutlet.selectedSegmentIndex == 0 {
return exchange.count
} else if segmentOutlet.selectedSegmentIndex == 1 {
return borrow.count
}else if segmentOutlet.selectedSegmentIndex == 2 {
return donation.count
} else if segmentOutlet.selectedSegmentIndex == 3 {
return sale.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if segmentOutlet.selectedSegmentIndex == 0 {
cell.textLabel?.text = exchange [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 1 {
cell.textLabel?.text = borrow [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 2 {
cell.textLabel?.text = donation [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 3 {
cell.textLabel?.text = sale [indexPath.row].passTitle
}
return cell
}
func getDataDonation(){
donation.removeAll()
db.collection("userDonationDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.donation.append(finalProject.donation(passTitle3:data["BookTitle"] as! String , passDes3: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataSale(){
sale.removeAll()
db.collection("userSaleDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.sale.append(finalProject.sale(passTitle4:data["BookTitle"] as! String , passDes4: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataExchange(){
exchange.removeAll()
db.collection("userExchangeDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.exchange.append(finalProject.exchange(passTitle1:data["BookTitle"] as! String , passDes1: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataBorrow(){
borrow.removeAll()
db.collection("userBorrowDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.borrow.append(finalProject.borrow(passTitle2:data["BookTitle"] as! String , passDes2: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
Note... I tried to do this but it didn't work
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
vc.recivedB = borrow[indexPath.row]
vc.recivedD = donation[indexPath.row]
vc.recivedS = sale[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
This is the struct,
I created a struct for each index
public struct exchange {
var passTitle : String
var passDes : String
init (passTitle1:String, passDes1:String) {
self.passTitle = passTitle1
self.passDes = passDes1
}
}
public struct borrow {
var passTitle : String
var passDes : String
init (passTitle2:String, passDes2:String) {
self.passTitle = passTitle2
self.passDes = passDes2
}
}
public struct donation {
var passTitle : String
var passDes : String
init (passTitle3:String, passDes3:String) {
self.passTitle = passTitle3
self.passDes = passDes3
}
}
public struct sale {
var passTitle : String
var passDes : String
init (passTitle4:String, passDes4:String) {
self.passTitle = passTitle4
self.passDes = passDes4
}
}
this is the last vc
import UIKit
import FirebaseStorage
import Firebase
import FirebaseFirestore
import SDWebImage
class ViewController10: UIViewController {
#IBOutlet weak var userBookTitle: UILabel!
#IBOutlet weak var userBookDescription: UILabel!
var recivedE:exchange?
var recivedB:borrow?
var recivedD:donation?
var recivedS:sale?
override func viewDidLoad() {
super.viewDidLoad()
userBookTitle.text = recivedE?.passTitle
userBookDescription.text = recivedE?.passDes
}
}
Note... I tried to do this but it didn't work
override func viewDidLoad() {
super.viewDidLoad()
if let et = recivedE?.passTitle ,
let ed = recivedE?.passDes{
userBookTitle.text = et
userBookDescription.text = ed
}
else if let bt = recivedB?.passTitle ,
let bd = recivedB?.passDes {
userBookTitle.text = bt
userBookDescription.text = bd
}
else if let dt = recivedD?.passTitle ,
let dd = recivedD?.passDes {
userBookTitle.text = dt
userBookDescription.text = dd
}
else if let st = recivedS?.passTitle ,
let sd = recivedS?.passDes {
userBookTitle.text = st
userBookDescription.text = sd
}
}
and this also not working
override func viewDidLoad() {
super.viewDidLoad()
userBookTitle.text = recivedE?.passTitle
userBookDescription.text = recivedE?.passDes
userBookTitle.text = recivedB?.passTitle
userBookDescription.text = recivedB?.passDes
userBookTitle.text = recivedD?.passTitle
userBookDescription.text = recivedD?.passDes
userBookTitle.text = recivedS?.passTitle
userBookDescription.text = recivedS?.passDes
}
help me, please
In both of your numberOfRowsInSection and cellForRowAt functions, you are checking the selected segment index to determine which data to use:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentOutlet.selectedSegmentIndex == 0 {
return exchange.count
} else if segmentOutlet.selectedSegmentIndex == 1 {
return borrow.count
}else if segmentOutlet.selectedSegmentIndex == 2 {
return donation.count
} else if segmentOutlet.selectedSegmentIndex == 3 {
return sale.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if segmentOutlet.selectedSegmentIndex == 0 {
cell.textLabel?.text = exchange [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 1 {
cell.textLabel?.text = borrow [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 2 {
cell.textLabel?.text = donation [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 3 {
cell.textLabel?.text = sale [indexPath.row].passTitle
}
return cell
}
However, in didSelectRowAt, you only use the exchange data:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
If you implement the same if / else if structure in didSelectRowAt you should get the desired results.
first I want to tell you what's my goal:
It should be possible for my app users to tap the + or - Stepper in each ProductTableViewCell to add or remove products to/from Cart.
In the NewOrderViewController where the productTableView is embedded there should be a label for showing the user how many products are in Cart at all. I named it totalProductCountLabel.
Also there should be a label named totalProductPriceLabel, to show the price for all products in Cart. The Cart should be updated every time the user taps the stepper inside a cell, and when the product.counter value is 0, then the product should be automatically removed from Cart.
Yesterday I've had a solution which works perfect:
ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CartSelection {
var totalProductCount = 0
var timerEnabled = true
var timerCount = 0
#IBOutlet weak var testTableview: UITableView!
#IBOutlet weak var totalProductCountLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
var productArray = [Product]()
var cartDictionary = [String: Product]()
override func viewDidLoad() {
super.viewDidLoad()
testTableview.delegate = self
testTableview.dataSource = self
testTableview.allowsSelection = false
productArray.append(Product(name: "Bananen", count: 0, price: 1.09, uuid: UUID().uuidString))
productArray.append(Product(name: "Äpfel", count: 0, price: 0.81, uuid: UUID().uuidString))
productArray.append(Product(name: "Kirschen", count: 0, price: 6.34, uuid: UUID().uuidString))
productArray.append(Product(name: "Tomaten", count: 0, price: 2.68, uuid: UUID().uuidString))
productArray.append(Product(name: "Weintrauben", count: 0, price: 1.48, uuid: UUID().uuidString))
productArray.append(Product(name: "Schokolade", count: 0, price: 0.67, uuid: UUID().uuidString))
testTableview.reloadData()
timerEnabled = true
timerCount = 0
self.totalProductCountLabel.text = "Anzahl Produkte: 0 Stück"
self.totalProductPriceLabel.text = "Preis Produkte: 0.00 €"
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timerEnabled = false
timerCount = 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
timerEnabled = false
timerCount = 5
}
func startTimer() {
_ = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
if self.timerEnabled != false && self.timerCount < 4 {
self.testTableview.reloadData()
print("Die Produktliste wurde aktualisiert!")
self.timerCount += 1
} else {
timer.invalidate()
self.timerEnabled = true
self.timerCount = 0
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TestTableViewCell
cell.product = productArray[indexPath.row]
cell.productNameLabel.text = "\(cell.product.name)"
cell.productPriceLabel.text = "\(cell.product.price)" + " € / kg"
cell.productCountLabel.text = "\(cell.product.count)"
cell.cartSelectionDelegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 188
}
func addProductToCart(product: Product, uuid: String) {
timerEnabled = false
cartDictionary[uuid] = product
if cartDictionary[uuid]?.count == 0 {
cartDictionary.removeValue(forKey: uuid)
}
calculateTotal()
}
func calculateTotal() {
var totalProductCount = 0
var totalProductPrice = 0.00
for (_,value) in cartDictionary {
totalProductCount += value.count
totalProductPrice += value.totalPrice
}
self.totalProductCountLabel.text = "Anzahl Produkte: \(totalProductCount) Stück"
self.totalProductPriceLabel.text = "Preis Produkte: \(String(format: "%5.2f", totalProductPrice)) €"
self.totalProductCount = totalProductCount
if cartDictionary.isEmpty {
print("Der Einkaufswagen ist leer")
timerEnabled = true
timerCount = 0
startTimer()
}
}
#IBAction func orderButtonTapped(_ sender: UIButton) {
if totalProductCount != 0 {
showOrderConfirmation()
var priceLabel = 0.00
print("Im Einkaufwagen sind folgende Produkte:")
for (key,value) in cartDictionary {
priceLabel += value.totalPrice
print("Produkt: \(value.name) --> \(value.count) __ Produktkennung: \(key)")
}
print("Gesamtpreis: \(priceLabel)")
}
}
func showOrderConfirmation() {
let alert = UIAlertController(title: "Bestellung aufgeben?", message: nil, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Bestellung aufgeben", style: .default)
let cancelAction = UIAlertAction(title: "Bestellung bearbeiten", style: .destructive)
alert.addAction(okayAction)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
}
Product Model
import UIKit
struct Product {
var name = "Produkt"
var count = 0
var price = 0.00
var totalPrice: Double {
return Double((count)) * (price)
}
var uuid = "Example: 20EE8409-230C-4E69-B366-C2EEE03998AF"
}
protocol CartSelection {
func addProductToCart(product : Product, uuid : String)
}
TableViewCell
import UIKit
class TestTableViewCell: UITableViewCell {
var cartSelectionDelegate: CartSelection?
#IBOutlet weak var productCountLabel: UILabel!
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
#IBOutlet weak var stepper: UIStepper!
#IBAction func cellTrashButtonTapped(_ sender: UIButton) {
resetCell()
}
#IBAction func changeProductCountStepper(_ sender: UIStepper) {
productCountLabel.text = Int(sender.value).description
product.count = Int(sender.value)
let totalPriceForProduct = Double(product.count) * product.price
totalProductPriceLabel.text = "Produktgesamtpreis: \(String(format: "%5.2f", totalPriceForProduct)) €"
updateChanges()
}
func updateChanges() {
cartSelectionDelegate?.addProductToCart(product: product, uuid: product.uuid)
}
func resetCell() {
productCountLabel.text = "0"
product.count = 0
totalProductPriceLabel.text = "Produktgesamtpreis: 0.00 €"
stepper.value = 0
updateChanges()
}
override func awakeFromNib() {
super.awakeFromNib()
stepper.autorepeat = true
}
var product : Product!
var productIndex = 0
}
Now my products are stored in Firebase Firestore, so I don't need the append method anymore and using a query instead.
All works as before, my products are shown in the table.
First Problem:
My Outlets from the ViewController are all nil, when pressing the stepper, so I can't see my label counting anymore. (The one in the ViewController), the labels in the cell are working.
Second Problem:
In the first code I am using a dictionary to store all the products in it ("cartDictionary").
This works in the second code, too. But only for one product. The counter in the dictionary is updating if I only tap one cells stepper, but if I tap on another cells stepper, the whole dictionary is empty and it starts with the other product again.
I can't find a solution for this problem, I know the problem is something with my ViewController is not initialized when using my outlets, but if I initialize it my dataSource crashes.
It would be very nice if there's someone helping me, because I can't go on working the last days.
Thank you very much!
My code that's not working:
Product Model
import UIKit
import FirebaseFirestore
protocol CartSelection {
func addProductToCart(product : Product, uuid : String)
}
struct Product {
var documentID: String
var shopID: String
var productName: String
var productPrice: Double
var counter: Int
var uuid: String
var totalPrice: Double {
return Double((counter)) * (productPrice)
}
}
// MARK: - Firestore interoperability
extension Product: DocumentSerializable {
/// Initializes a shop with a documentID auto-generated by Firestore.
init(shopID: String,
productName: String,
productPrice: Double,
counter: Int,
uuid: String) {
let document = Firestore.firestore().shops.document()
self.init(documentID: document.documentID,
shopID: shopID,
productName: productName,
productPrice: productPrice,
counter: counter,
uuid: uuid)
}
/// Initializes a shop from a documentID and some data, from Firestore.
private init?(documentID: String, dictionary: [String: Any]) {
guard let shopID = dictionary["shopID"] as? String,
let productName = dictionary["productName"] as? String,
let productPrice = dictionary["productPrice"] as? Double,
let counter = dictionary["counter"] as? Int,
let uuid = dictionary["uuid"] as? String else { return nil }
self.init(documentID: documentID,
shopID: shopID,
productName: productName,
productPrice: productPrice,
counter: counter,
uuid: uuid)
}
init?(document: QueryDocumentSnapshot) {
self.init(documentID: document.documentID, dictionary: document.data())
}
init?(document: DocumentSnapshot) {
guard let data = document.data() else { return nil }
self.init(documentID: document.documentID, dictionary: data)
}
/// The dictionary representation of the restaurant for uploading to Firestore.
var documentData: [String: Any] {
return [
"shopID": shopID,
"productName": productName,
"productPrice": productPrice,
"counter": counter,
"uuid": uuid
]
}
}
Product TableViewCell
import UIKit
import FirebaseFirestore
class ProductTableViewCell: UITableViewCell {
var cartSelectionDelegate: CartSelection?
#IBOutlet weak var productCountLabel: UILabel!
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
#IBOutlet weak var stepper: UIStepper!
#IBAction func cellTrashButtonTapped(_ sender: UIButton) {
resetCell()
}
#IBAction func changeProductCountStepper(_ sender: UIStepper) {
productCountLabel.text = Int(sender.value).description
product.counter = Int(sender.value)
let totalPriceForProduct = Double(product.counter) * product.productPrice
totalProductPriceLabel.text = "Produktgesamtpreis: \(String(format: "%5.2f", totalPriceForProduct)) €"
updateChanges()
}
func updateChanges() {
cartSelectionDelegate?.addProductToCart(product: product, uuid: product.uuid)
}
func resetCell() {
productCountLabel.text = "0"
product.counter = 0
totalProductPriceLabel.text = "Produktgesamtpreis: 0.00 €"
stepper.value = 0
updateChanges()
}
override func awakeFromNib() {
super.awakeFromNib()
stepper.autorepeat = true
}
var product : Product!
var productIndex = 0
}
Product TableViewDataSource
import UIKit
import FirebaseFirestore
#objc class ProductTableViewDataSource: NSObject, UITableViewDataSource {
private let products: LocalCollection<Product>
var sectionTitle: String?
public init(products: LocalCollection<Product>) {
self.products = products
}
public convenience init(query: Query, updateHandler: #escaping ([DocumentChange]) -> ()) {
let collection = LocalCollection<Product>(query: query, updateHandler: updateHandler)
self.init(products: collection)
}
public func startUpdates() {
products.listen()
}
public func stopUpdates() {
products.stopListening()
}
subscript(index: Int) -> Product {
return products[index]
}
public var count: Int {
return products.count
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitle
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.TableView.productCell, for: indexPath) as! ProductTableViewCell
cell.product = products[indexPath.row]
cell.productNameLabel.text = "\(cell.product.productName)"
cell.productPriceLabel.text = "\(cell.product.productPrice)" + " € / kg"
cell.productCountLabel.text = "\(cell.product.counter)"
cell.cartSelectionDelegate = NewOrderViewController()
return cell
}
}
NewOrderViewController
import UIKit
import FirebaseFirestore
class NewOrderViewController: UIViewController, UITableViewDelegate, CartSelection {
#IBOutlet var productTableView: UITableView!
#IBOutlet weak var totalProductCountLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
private var shop: Shop!
var totalProductCount = 0
var timerEnabled = true
var timerCount = 0
var cartDictionary = [String: Product]()
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
productTableView.dataSource = dataSource
productTableView.delegate = self
query = baseQuery
productTableView.allowsSelection = false
productTableView.reloadData()
timerEnabled = true
timerCount = 0
totalProductCountLabel.text = "Anzahl Produkte: 0 Stück"
totalProductPriceLabel.text = "Preis Produkte: 0.00 €"
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setNeedsStatusBarAppearanceUpdate()
dataSource.startUpdates()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
dataSource.stopUpdates()
timerEnabled = false
timerCount = 0
}
// MARK: - DataSource and Query
private func dataSourceForQuery(_ query: Query) -> ProductTableViewDataSource {
return ProductTableViewDataSource(query: query) { [unowned self] (changes) in
self.productTableView.reloadData()
}
}
lazy private var dataSource: ProductTableViewDataSource = {
return dataSourceForQuery(baseQuery)
}()
lazy private var baseQuery: Query = {
Firestore.firestore().products.whereField("shopID", isEqualTo: shop.documentID)
}()
fileprivate var query: Query? {
didSet {
dataSource.stopUpdates()
productTableView.dataSource = nil
if let query = query {
dataSource = dataSourceForQuery(query)
productTableView.dataSource = dataSource
dataSource.startUpdates()
}
}
}
// MARK: - Delegate Method
func addProductToCart(product: Product, uuid: String) {
timerEnabled = false
cartDictionary[uuid] = product
if cartDictionary[uuid]?.counter == 0 {
cartDictionary.removeValue(forKey: uuid)
}
calculateTotal()
}
// MARK: - Actions
#IBAction func orderButtonTapped(_ sender: UIButton) {
if totalProductCount != 0 {
showOrderConfirmation()
var priceLabel = 0.00
print("Im Einkaufwagen sind folgende Produkte:")
for (key,value) in cartDictionary {
priceLabel += value.totalPrice
print("Produkt: \(value.productName) --> \(value.counter) __ Produktkennung: \(key)")
}
print("Gesamtpreis: \(priceLabel)")
}
}
// MARK: - Functions
func showOrderConfirmation() {
let alert = UIAlertController(title: "Bestellen?", message: nil, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Bestellung aufgeben", style: .default)
let cancelAction = UIAlertAction(title: "Bestellung bearbeiten", style: .destructive)
alert.addAction(okayAction)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
func calculateTotal() {
var totalProductCount = 0
var totalProductPrice = 0.00
for (_,value) in cartDictionary {
totalProductCount += value.counter
totalProductPrice += value.totalPrice
}
self.totalProductCountLabel.text = "Anzahl Produkte: \(totalProductCount) Stück"
self.totalProductPriceLabel.text = "Preis Produkte: \(String(format: "%5.2f", totalProductPrice)) €"
if cartDictionary.isEmpty {
print("Der Einkaufswagen ist leer")
timerEnabled = true
timerCount = 0
startTimer()
}
}
func startTimer() {
_ = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
if self.timerEnabled != false && self.timerCount < 4 {
self.productTableView.reloadData()
print("Die Produktliste wurde aktualisiert!")
self.timerCount += 1
} else {
timer.invalidate()
self.timerEnabled = true
self.timerCount = 0
}
}
}
// MARK: - TableView Delegate
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 188
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
timerEnabled = false
timerCount = 5
}
// MARK: - Navigation
static func fromStoryboard(_ storyboard: UIStoryboard = UIStoryboard(name: Constants.StoryboardID.main, bundle: nil),
forShop shop: Shop) -> NewOrderViewController {
let controller = storyboard.instantiateViewController(withIdentifier: Constants.StoryboardID.newOrderViewController) as! NewOrderViewController
controller.shop = shop
return controller
}
}
All problems fixed by making a static instance of my NewOrderViewController!
class NewOrderViewController: UIViewController, UITableViewDelegate, CartSelection {
#IBOutlet var productTableView: UITableView!
#IBOutlet weak var totalProductCountLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
private var shop: Shop!
var totalProductCount = 0
var timerEnabled = true
var timerCount = 0
var cartDictionary = [String: Product]()
static var instance: NewOrderViewController?
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
NewOrderViewController.instance = self
productTableView.dataSource = dataSource
productTableView.delegate = self
query = baseQuery
productTableView.allowsSelection = false
productTableView.reloadData()
timerEnabled = true
timerCount = 0
totalProductCountLabel.text = "Anzahl Produkte: 0 Stück"
totalProductPriceLabel.text = "Preis Produkte: 0.00 €"
}
I have data coming from Firebase and when the data is loaded I either want the an image to be hidden or shown based on some logic in my custom cell. It works perfectly fine when the data isn't being filtered but the second I type in the search bar or change the scope bar to a different index the image doesn't behave right.
For example: Index 0 should not have the image and index 1 should. Which is how it displays when it first loads. However, when I search I know the previous index 1 (now index 0) should still have it's image but it doesn't. BUT if I click to go to the detail controller it brings me to the right page. It's like it loads all the accurate info but does the logic on the original index 0. I would love some help as I have been searching for an answer FOREVER. Thank you in advance!
tableViewCell:
class SearchTalentCell: UITableViewCell {
#IBOutlet weak var userProfileImage: UIImageView!
#IBOutlet weak var talentUserName: UILabel!
#IBOutlet weak var selectedImg: UIImageView!
#IBOutlet weak var inviteSentImg: UIImageView!
var prospectRef: FIRDatabaseReference!
//#IBOutlet weak var radioButton: UIButton!
var currentTalent: UserType!
//var delegate: SearchCellDelegate?
func setTalent(talent: UserType) {
currentTalent = talent
currentTalent.userKey = talent.userKey
}
override func awakeFromNib() {
super.awakeFromNib()
let tap = UITapGestureRecognizer(target: self, action: #selector(selectTapped))
tap.numberOfTapsRequired = 1
selectedImg.addGestureRecognizer(tap)
selectedImg.isUserInteractionEnabled = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
/*#IBAction func radioButtonTapped(_ sender: Any) {
delegate?.didTapRadioButton(userKey: currntTalent.userKey, searchSelected: currntTalent.searchSelected!.rawValue, radioButton: radioButton)
}*/
func configureCell(user: UserType, img: UIImage? = nil) {
prospectRef = Cast.REF_PRE_PRODUCTION_CASTING_POSITION.child(ProjectDetailVC.currentProject).child(FIRDataCast.prospect.rawValue).child(CastingDetailVC.positionName).child(user.userKey)
//setTalent(talent: user)
self.talentUserName.text = "\(user.firstName) \(user.lastName)"
//self.inviteSentImg.image = UIImage(named: "inviteSent")
//user.adjustSearchSelected(talent: user, radioButton: radioButton)
prospectRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
print("**Image hidden")
} else {
self.inviteSentImg.image = UIImage(named: "inviteSent")
print("**Image shown")
}
})
//Image Caching
if img != nil {
self.userProfileImage.image = img
} else {
if let imageURL = user.profileImage {
let ref = FIRStorage.storage().reference(forURL: imageURL)
ref.data(withMaxSize: 2 * 1024 * 1024, completion: { (data, error) in
if error != nil {
print("ZACK: Unable to download image from Firebase Storage")
} else {
print("ZACK: Image downloaded from Firebase Storage")
if let imgData = data {
if let img = UIImage(data: imgData) {
self.userProfileImage.image = img
SearchTalentVC.userProfileImageCache.setObject(img, forKey: imageURL as NSString)
}
}
}
})
}
}
}
Viewcontroller:
class SearchTalentVC: UITableViewController/*, SearchCellDelegate*/ {
var searchingRole = [Cast]()
var unfilteredTalent = [UserType]()
var filteredTalent = [UserType]()
var selectedTalent = [UserType]()
var matchingTalentUserKeys = [String]()
var isFiltered = false
var prospectRef: FIRDatabaseReference!
static var userProfileImageCache: NSCache<NSString, UIImage> = NSCache()
let searchController = UISearchController(searchResultsController: nil)
//#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Talent"
searchController.searchBar.barStyle = .black
navigationItem.searchController = searchController
definesPresentationContext = true
searchController.searchBar.scopeButtonTitles = ["All", "Role Specific"]
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
getTalentProfiles()
}
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredTalent = unfilteredTalent.filter({ (talent : UserType) -> Bool in
let doesTalentMatch = (scope == "All") || doesUserKeyMatch(talent: talent.userKey)
if searchBarIsEmpty() {
return doesTalentMatch
} else {
let fullName = "\(talent.firstName) \(talent.lastName)"
return doesTalentMatch && fullName.lowercased().contains(searchText.lowercased())
}
})
tableView.reloadData()
}
func doesUserKeyMatch(talent: String) -> Bool {
self.filterRoleFeature()
return matchingTalentUserKeys.contains(talent)
}
func isSearching() -> Bool {
let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if isSearching() {
return filteredTalent.count
} else {
return unfilteredTalent.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "userSearchCell"
if let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? SearchTalentCell {
var talent: UserType
if isSearching() {
print("we are searching")
talent = self.filteredTalent[indexPath.row]
print("indexPath: \(indexPath.row)")
} else {
print("we are not searching")
talent = self.unfilteredTalent[indexPath.row]
}
if let imageURL = talent.profileImage {
if let img = SearchTalentVC.userProfileImageCache.object(forKey: imageURL as NSString) {
cell.configureCell(user: talent, img: img)
} else {
cell.configureCell(user: talent)
//cell.delegate = self
}
return cell
} else {
cell.configureCell(user: talent)
//cell.delegate = self
return SearchTalentCell()
}
} else {
return SearchTalentCell()
}
}
extension SearchTalentVC: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
self.tableView.reloadData()
}
}
extension SearchTalentVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
If you are hidding image in If part then you should put logic of showing image also in else block. See if this solve your problem.
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
print("**Image hidden")
} else {
self.inviteSentImg.isHidden = false
self.inviteSentImg.image = UIImage(named: "inviteSent")
print("**Image shown")
}
I am a beginner to Xcode and Swift and I am currently creating an application where the user adds a person on the application and after that it right the amount of money they owe that person or that person owes him/her.
Note: I have used core data to store all the value
I actually want to change the value of a variable when switch is on and off. For instance, in the following I want the "amount" to be negative when the switch is on and positive when it is off. Also, when I try to do this and send amount variable to previous view controller I can't send the value depending on the UISwitch because it always shows positive. I am trying to find a solution to this from past 3 days therefore can you please help me? Thanks a lot in advance
Owe ViewController
import UIKit
class NewOweTableViewController: UIViewController {
#IBOutlet weak var titleTextField: UITextField!
#IBOutlet weak var locationTextField: UITextField!
#IBOutlet weak var amountTextField: UITextField!
#IBOutlet weak var datePicker: UIDatePicker!
let context = (UIApplication.shared.delegate as!
AppDelegate).persistentContainer.viewContext
var owe: Owe?
var dataInfo: [Owe] = []
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.viewWithTag(1)?.isHidden = true
let saveBTN = UIBarButtonItem(barButtonSystemItem:UIBarButtonSystemItem.save, target:self,
action: #selector(saveButtonTapped(_:)))
let deleteBTN = UIBarButtonItem(barButtonSystemItem:UIBarButtonSystemItem.trash, target:self,
action: #selector(deleteButtonTapped(_:)))
self.navigationItem.rightBarButtonItems = [saveBTN, deleteBTN]
if !dataInfo.isEmpty {
titleTextField.text = dataInfo[0].name
amountTextField.text = (NSString(format: "%.2f", (dataInfo[0].amount) as CVarArg) as String)
locationTextField.text = dataInfo[0].location
datePicker.date = dataInfo[0].date!
}
}
#objc func saveButtonTapped(_ sender: UIButton){
if !dataInfo.isEmpty{
let data = dataInfo[0]
data.name = titleTextField.text
data.amount = Double(amountTextField.text!)!
data.location = locationTextField.text
data.date = datePicker.date
}
else if titleTextField.text == "" || amountTextField.text == "" || locationTextField.text == "" {
return
}
else{
let data = Owe(context: context)
data.name = titleTextField.text
data.amount = Double(amountTextField.text!)!
data.location = locationTextField.text
data.date = datePicker.date
}
do {
try context.save()
navigationController?.popViewController(animated: true)
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
#objc func deleteButtonTapped(_ sender: UIButton){
if !dataInfo.isEmpty{
let data = dataInfo[0]
context.delete(data)
do {
try context.save()
navigationController?.popViewController(animated: true)
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
#IBAction func oweSwitch(_ sender: UISwitch) {
if sender.isOn {
owe?.amount = (owe?.amount)! * (-1)
amountTextField.textColor = UIColor.green
} else {
owe?.amount = (owe?.amount)! * (1)
amountTextField.textColor = UIColor.red
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Previous View Controller
import UIKit
class PersonDetailTableViewController: UITableViewController {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var totalLabel: UILabel?
var person: People?
var owe: Owe?
#IBOutlet var personTable: UITableView!
var dataInfo: [Owe] = []
var selectedObject: [Owe] = []
var balanceAmount = "Balance: "
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dataInfo.count)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = personTable
.dequeueReusableCell(withIdentifier: "detailsCell", for: indexPath)
cell.textLabel?.text = dataInfo[indexPath.row].name
cell.detailTextLabel?.text = "₹ \(dataInfo[indexPath.row].amount)"
if dataInfo[indexPath.row].amount < 0 {
cell.detailTextLabel?.textColor = UIColor.red
} else {
cell.detailTextLabel?.textColor = UIColor.green
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedObject = [dataInfo[indexPath.row]]
performSegue(withIdentifier: "addOweDetails", sender: nil)
tableView.deselectRow(at: indexPath, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
personTable.dataSource = self
addTotalToNav()
print(dataInfo as Any)
}
// MARK: - Table view data source
func addTotalToNav() -> Void {
if let navigationBar = self.navigationController?.navigationBar {
let totalFrame = CGRect(x: 10, y: 0, width: navigationBar.frame.width/2, height: navigationBar.frame.height)
totalLabel = UILabel(frame: totalFrame)
totalLabel?.text = balanceAmount
totalLabel?.tag = 1
totalLabel?.font = UIFont.boldSystemFont(ofSize: 14)
totalLabel?.textColor = UIColor.red
// navigationBar.large = totalLabel?.text
self.title = totalLabel?.text
}
}
func getData() -> Void {
do{
dataInfo = try context.fetch(Owe.fetchRequest())
var total:Double = 0.00
for i in 0 ..< dataInfo.count {
total += dataInfo[i].amount as! Double
}
balanceAmount = "Balance: ₹" + (NSString(format: "%.2f", total as CVarArg) as String)
}
catch{
print("Fetching Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
personTable.reloadData()
if (self.navigationController?.navigationBar.viewWithTag(1)?.isHidden == true){
self.navigationController?.navigationBar.viewWithTag(1)?.removeFromSuperview()
addTotalToNav()
}
}
}
Core Data for owe
import UIKit
import CoreData
#objc(Owe)
public class Owe: NSManagedObject {
var date: Date? {
get{
return rawDate as Date?
}
set {
rawDate = newValue as NSDate?
}
}
convenience init?(name: String?, location: String?, amount: Double, date: Date?) {
let appDelegate = UIApplication.shared.delegate as? AppDelegate
guard let context = appDelegate?.persistentContainer.viewContext
else {
return nil
}
self.init(entity: Owe.entity(), insertInto: context)
self.name = name
self.location = location
self.amount = amount
self.date = date
}
}
Hi there and welcome to the Swift Community!
If I understand correctly, you are trying to propagates updates backwards from NewOweTableViewController to PersonDetailTableViewController. If that is the case, an easy way to achieve this with your MVC architecture is by passing a closure to NewOweTableViewController when you initialize it in PersonDetailTableViewController.
In order to do so,
Update NewOweTableViewController and add a closure property.
class NewOweTableViewController: UIViewController {
// ...
var switchValueUpdate: ((Bool) -> ())?
// ...
}
Make sure you call this closure inside your #IBAction that you link to your switch in NewOweTableViewController
#IBAction func oweSwitch(_ sender: UISwitch) {
if sender.isOn {
owe?.amount = (owe?.amount)! * (-1)
amountTextField.textColor = UIColor.green
} else {
owe?.amount = (owe?.amount)! * (1)
amountTextField.textColor = UIColor.red
}
switchValueUpdate?(sender.isOn)
}
update PersonDetailTableViewController to set the closure
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
vc.switchValueUpdate = { (isOn) in
// Here you go, update PersonDetailTableViewController to reflect changes related to the switch!
}
}
That's it! Let me know if you have any question on that code, hope it helps!
I have one screen like the following picture:
I uploaded list with student name by using custom cell as you are seeing and I want when click on save button save the status of student in array , I initialized array with 0 for all student at the first time and when the status of switch is enabled then this value at the clicked cell index converted to 1 but I couldn't make that when the click action happened on switch this is only now happening when click on the cell ( row ) how I can do the same thing when only change the status of switch to update the array without click on complete row at table
Code of main view :
import UIKit
class teacherAttendanceVC: UIViewController , UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var studentlistTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String?
var classID: String?
var branchID: String?
var normal_id = [String]()
var student_name = [String]()
var student_attendance = [String]()
//Sent Data
var n_id = ""
var stu_name = ""
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
override func viewDidLoad() {
super.viewDidLoad()
studentlistTable.delegate = self
studentlistTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
classID = prefs.objectForKey("ClassID")as! String
branchID = prefs.objectForKey("BranchID")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
self.studentlistTable.reloadData()
})
});
}
override func viewDidAppear(animated: Bool) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return normal_id.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = self.studentlistTable.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! teacherAttendanceCell
cell.studentNameLabel.text = student_name[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
student_attendance[indexPath.row] = currentCell.status
}
#IBAction func saveButton(sender: AnyObject) {
print(student_attendance) // this only to ensure from the final array before sending to server
}
func loadList()
{
var normallink = "myurl"
normallink = normallink + "?classid=" + self.classID! + "&branchid=" + self.branchID!
print(normallink)
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let no_id = onedata["id"] as? String {
normal_id.append(no_id)
}
if let s_name = onedata["studentName"] as? String {
student_name.append(s_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
if(normal_id.count != 0)
{
for i in 1...self.normal_id.count
{
self.student_attendance.append("0")
}
}
print(normal_id.count)
print(student_name.count)
}
}
Cell Code :
class teacherAttendanceCell: UITableViewCell {
#IBOutlet weak var studentNameLabel: UILabel!
#IBOutlet weak var attendSwitch: UISwitch!
var status:String = ""
override func awakeFromNib() {
super.awakeFromNib()
if(attendSwitch.on)
{
status = "1"
print("ON")
}
else{
status = "0"
print("OFF")
}
attendSwitch.addTarget(self, action: "stateChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func stateChanged(switchState: UISwitch) {
if switchState.on {
status = "1"
print("ON")
} else {
status = "0"
print("OFF")
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func attendSwitchChanged(sender: AnyObject) {
}
}
Updated:
Main View Controller:
import UIKit
class teacherAttendanceVC: UIViewController , UITableViewDataSource,UITableViewDelegate,CellInfoDelegate {
#IBOutlet weak var studentlistTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String?
var classID: String?
var branchID: String?
var normal_id = [String]()
var student_name = [String]()
var student_attendance = [String]()
//Sent Data
var n_id = ""
var stu_name = ""
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
override func viewDidLoad() {
super.viewDidLoad()
studentlistTable.delegate = self
studentlistTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
classID = prefs.objectForKey("ClassID")as! String
branchID = prefs.objectForKey("BranchID")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
self.studentlistTable.reloadData()
})
});
}
override func viewDidAppear(animated: Bool) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return normal_id.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = self.studentlistTable.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! teacherAttendanceCell
cell.delegate = self
cell.studentNameLabel.text = student_name[indexPath.row]
student_attendance[indexPath.row] = cell.status
//print(student_attendance.count)
//let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
// student_attendance.append(cell.status)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
// let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
// student_attendance[indexPath.row] = currentCell.status
//print("OK Status here!" + String(student_attendance.count))
}
#IBAction func saveButton(sender: AnyObject) {
print(student_attendance)
}
func loadList()
{
var normallink = "mylinkhere"
normallink = normallink + "?classid=" + self.classID! + "&branchid=" + self.branchID!
print(normallink)
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let no_id = onedata["id"] as? String {
normal_id.append(no_id)
}
if let s_name = onedata["studentName"] as? String {
student_name.append(s_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
if(normal_id.count != 0)
{
for i in 1...self.normal_id.count
{
self.student_attendance.append("0")
}
}
print(normal_id.count)
print(student_name.count)
}
func processThatNumber(theStatus: String) {
print("out : \(theStatus)")
}
}
protocol CellInfoDelegate {
func processThatNumber(theStatus: String)
}
Cell View Controller:
import UIKit
class teacherAttendanceCell: UITableViewCell{
#IBOutlet weak var studentNameLabel: UILabel!
#IBOutlet weak var attendSwitch: UISwitch!
var status:String = ""
var delegate: CellInfoDelegate?
override func awakeFromNib() {
super.awakeFromNib()
if(attendSwitch.on)
{
status = "1"
print("ON")
}
else{
status = "0"
print("OFF")
}
attendSwitch.addTarget(self, action: "stateChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func stateChanged(switchState: UISwitch) {
if switchState.on {
status = "1"
print("ON")
} else {
status = "0"
print("OFF")
}
if let delegate = self.delegate {
delegate.processThatNumber(self.status)
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func attendSwitchChanged(sender: AnyObject) {
}
}
There are few ways to do this: using closure or delegate, but I preferred to use delegate.
Create a delegate for your teacherAttendanceCell cell like in this answer https://stackoverflow.com/a/25792213/2739795
Make you teacherAttendanceVC conforms the delegate
Each time when cellForRowAtIndexPath calls set cell.delegate = self. Also return the cell into your delegate method
Call method from delegate insidestateChanged
And when delegate method calls you can get an index if switched cell
tableView.indexPathForCell(cellFromParam)