iOS development Swift Custom Cells - ios

I'm developing an app in Swift and I have problem with Custom Cells. I have one Custom Cell and when you click on Add button it creates another Custom Cell. Cell has 3 textfields, and 2 buttons. Those textfields are name, price, and amount of the ingredient of meal that I am creating. When I use only one Custom Cell or add one more to make it two, the data is stored properly. But when I add 2 Custom Cell (3 Custom Cells in total) I have problem of wrong price, only last two ingredients are calculated in price. When I add 3 Custom Cells (4 Custom Cells in total) it only recreates first cell with populated data like in first cell.
On finish button tap, I get an fatal error: Found nil while unwrapping Optional value.
View Controller
import UIKit
import CoreData
class AddMealViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var mealNameTF: UITextField!
#IBOutlet weak var addMealsCell: UITableViewCell!
#IBOutlet weak var finishButton: UIButton!
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var addButton: UIButton!
#IBOutlet weak var addMealTableView: UITableView!
#IBOutlet weak var productPrice: UILabel!
let currency = "$" // this should be determined from settings
var priceTotal = "0"
override func viewDidLoad() {
super.viewDidLoad()
addMealTableView.delegate = self
addMealTableView.dataSource = self
borderToTextfield(textField: mealNameTF)
mealNameTF.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return true;
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return counter
}
var counter = 1
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return counter
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"addMealsCell", for: indexPath) as! AddMealsTableViewCell
borderToTextfield(textField: (cell.amountTF)!)
borderToTextfield(textField: (cell.ingredientNameTF)!)
//borderToTextfield(textField: cell.normativeTF)
borderToTextfield(textField: (cell.priceTF)!)
return cell
}
#IBAction func addButton(_ sender: UIButton) {
counter += 1
addMealTableView.register(AddMealsTableViewCell.self, forCellReuseIdentifier: "addMealsCell")
addMealTableView.reloadData()
}
#IBAction func resetButton(_ sender: UIButton) {
mealNameTF.text = ""
for c in 0..<counter{
let indexPath = IndexPath(row: c, section:0)
let cell = addMealTableView.cellForRow(at: indexPath) as! AddMealsTableViewCell
cell.amountTF.text = ""
cell.ingredientNameTF.text = ""
// cell.normativeTF.text = ""
cell.priceTF.text = ""
}
productPrice.text = "\(currency)0.00"
priceTotal = "0"
counter = 1
}
#IBAction func finishButton(_ sender: UIButton) {
for c in (0..<counter){
if let cell = addMealTableView.cellForRow(at: IndexPath(row: c, section: 0)) as? AddMealsTableViewCell {
cell.amountTF.delegate = self
cell.ingredientNameTF.delegate = self
// cell.normativeTF.delegate = self
cell.priceTF.delegate = self
guard cell.priceTF.text?.isEmpty == false && cell.amountTF.text?.isEmpty == false && mealNameTF.text?.isEmpty == false && cell.ingredientNameTF.text?.isEmpty == false
else {
return
}
if cell.priceTF.text?.isEmpty == false{
// if (true) {
let tfp = Double((cell.priceTF.text!))!*Double((cell.amountTF.text!))!
var ttp = Double(priceTotal)
ttp! += tfp
priceTotal = String(ttp!)
// }
}}
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newMeal = NSEntityDescription.insertNewObject(forEntityName: "Meal", into: context)
let mealName = mealNameTF.text
newMeal.setValue(mealName, forKey: "name")
newMeal.setValue(priceTotal, forKey: "price")
do {
try context.save()
print("Spremljeno")
} catch {
print("Neki error")
}
productPrice.text = currency + priceTotal
}
#IBAction func addNewIngredientButton(_ sender: UIButton) {
}
func borderToTextfield(textField: UITextField){
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.white.cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)
border.borderWidth = width
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true
textField.tintColor = UIColor.white
textField.textColor = UIColor.white
textField.textAlignment = .center
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return true;
}
}
Cell
class AddMealsTableViewCell: UITableViewCell, UITextFieldDelegate{
#IBOutlet weak var DropMenuButton: DropMenuButton!
#IBOutlet weak var addNewIngredient: UIButton!
#IBOutlet weak var ingredientNameTF: UITextField!
// #IBOutlet weak var normativeTF: UITextField!
#IBOutlet weak var amountTF: UITextField!
#IBOutlet weak var priceTF: UITextField!
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.endEditing(true)
return true;
}
override func prepareForReuse() {
self.amountTF.text = ""
self.priceTF.text = ""
self.ingredientNameTF.text = ""
}
#IBAction func DropMenuButton(_ sender: DropMenuButton) {
DropMenuButton.initMenu(["kg", "litre", "1/pcs"], actions: [({ () -> (Void) in
print("kg")
sender.titleLabel?.text = "kg"
}), ({ () -> (Void) in
print("litre")
sender.titleLabel?.text = "litre"
}), ({ () -> (Void) in
print("1/pcs")
sender.titleLabel?.text = "1/pcs"
})])
}
#IBAction func addNewIngredient(_ sender: UIButton) {
let name = ingredientNameTF.text
let amount = amountTF.text
let price = priceTF.text
// let normative = normativeTF.text
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newIngredient = NSEntityDescription.insertNewObject(forEntityName: "Ingredient", into: context)
newIngredient.setValue(name, forKey: "name")
// newIngredient.setValue(normative, forKey: "normative")
newIngredient.setValue(amount, forKey: "amount")
newIngredient.setValue(price, forKey: "price")
do {
try context.save()
print("Spremljeno")
} catch {
print("Neki error")
}
}
}

Your code is very difficult to read, but I suspect the problem may be here:
func numberOfSections(in tableView: UITableView) -> Int {
return counter
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return counter
}
You're returning the same number of rows for both the sections and rows for sections. So if you have 1 ingredient you are saying there is 1 section with 1 row. But if you have 2 ingredients you are saying there are 2 sections, each with 2 cells (4 cells total).
There are many other things to fix with your code, here are a few:
The biggest thing is that you are making this very difficult with the counter variable you have. If instead you have an array of ingredients
var ingredients = [Ingredient]()
You can use that to setup everything for the count of your table. Something like this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ingredients.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"addMealsCell", for: indexPath) as! AddMealsTableViewCell
let ingredient = ingredients[indexPath.row]
cell.ingredientNameTF.text = ingredient.name
cell.normativeTF.text = ingredient.normative
cell.amountTF.text = ingredient.amount
cell.priceTF.text = ingredient.price
return cell
}
All of these can be set in interface builder (you dont need lines of code in your view did load for them):
addMealTableView.delegate = self
addMealTableView.dataSource = self
mealNameTF.delegate = self
This line should be in your viewDidLoad function, you only need to register the class once, you're doing it everytime add is pressed.
addMealTableView.register(AddMealsTableViewCell.self, forCellReuseIdentifier: "addMealsCell")
Your action names should be actions
#IBAction func addButtonPressed(_ sender: UIButton)
#IBAction func resetButtonPressed(_ sender: UIButton)
#IBAction func finishButtonPressed(_ sender: UIButton)
Thanks. Now when that ViewController loads I have no cells. My array is now empty so I have to implement some code to addButton which creates another cell and reloads tableView. How can I do that?
You just need to add a new ingredient object to the ingredients array and reload the data of the table view.
#IBAction func addButtonPressed(_ sender: UIButton) {
let newIngredient = Ingredient()
ingredients.append(newIngredient)
tableView.reloadData()
}

Related

Custom TableViewCell lose its own variable when scrolling

I have the following Custom TableViewCell
The red(minus) and green(plus) button counts the left label "1"(in code snippet var myQuantity). If I scroll up and down in the tableView the variable myQuantity is always reset to 1 for selected cells.
I read that I have to set the myQuantity in the cellForRowAt method. But how can I set the cell value with its own class variable when its changed via green and red button?
Here my Custom Cell Class:
class ArticleTableViewCell: UITableViewCell {
#IBOutlet var leftLabel: UILabel!
#IBOutlet var rightLabel: UILabel!
#IBOutlet var quantityLabel: UILabel!
var myQuantity = 0
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.quantityLabel.text = String(self.myQuantity)
self.leftLabel.sizeToFit()
self.rightLabel.sizeToFit()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if selected {
self.myQuantity = 1
} else {
self.myQuantity = 0
}
self.quantityLabel.text = String(self.myQuantity)
}
#IBAction func addButton(_ sender: UIButton) {
if !self.isSelected { return }
self.myQuantity += 1
self.quantityLabel.text = String(self.myQuantity)
}
#IBAction func minusButton(_ sender: UIButton) {
if !self.isSelected { return }
if self.myQuantity == 1 { return }
self.myQuantity -= 1
self.quantityLabel.text = String(self.myQuantity)
}}
Here the cellForRowAt Method in my ViewController:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "customArticleCell", for: indexPath) as? ArticleTableViewCell {
let name: String! = categoryArticles[indexPath.row].name
let price = categoryArticles[indexPath.row].price
let price2f = String(format: "%.2f", price)
cell.accessoryType = .none
cell.leftLabel.text = name!
cell.rightLabel.text = "\(price2f) €"
if cell.isSelected {
cell.accessoryType = .checkmark
}
return cell
}
}
class ArticleTableViewCell: UITableViewCell {
#IBOutlet var leftLabel: UILabel!
#IBOutlet var rightLabel: UILabel!
#IBOutlet var quantityLabel: UILabel!
var addAction: (()->())?
var minusAction: (()->())?
override func awakeFromNib() {
super.awakeFromNib()
self.selectionStyle = .none
}
func setupCellWith(data: CategoryArticle) {
self.accessoryType = (data.isSelected == true) ? .checkmark : .none
self.leftLabel.text = data.name
let price2f = String(format: "%.2f", data.price)
self.rightLabel.text = "\(price2f) €"
}
#IBAction func addButton(_ sender: UIButton) {
self.addAction?()
}
#IBAction func minusButton(_ sender: UIButton) {
self.minusAction?()
}
}
struct CategoryArticle {
let name: String
let price: Double
var isSelected: Bool?
var quantity: Int?
}
let categoryArticles: [CategoryArticle] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customArticleCell", for: indexPath) as! ArticleTableViewCell
let categoryArticle = categoryArticles[indexPath.row]
cell.setupCellWith(data: categoryArticle)
cell.minusAction = { [weak self] in
// Action you want to do like decrease the count in the model at indexPath.row and set selection in th model too and reload the tableView cell
}
cell.addAction = { [weak self] in
// Action you want to do like increase the count in the model at indexPath.row and set selection in th model too and reload the tableView cell
}
return cell
}

How to update UILabel on a button click in UITableViewCell in swift 4 and xcode 9? [duplicate]

This question already has answers here:
Swift - Increment Label with Stepper in TableView Cell
(2 answers)
Closed 4 years ago.
I am building a food ordering app. In which, there are increment and decrement buttons and a UILabel to display quantity. I want to update the quantity label on increment and decrement buttons click. Image of which is attached.
A snippet of My ViewController is
protocol GondolaTableViewCellDelegate: class {
func tableViewCellAddToCart(_ sender: ItemDetailTableViewCell)
func tableViewCellIncrement(_ sender: ItemDetailTableViewCell)
func tableViewCellDecrement(_ sender: ItemDetailTableViewCell)
var tableViewCellQuantity: String { get set }
}
class ItemDetailTableViewCell: UITableViewCell {
//itemTableCell
var quantity = 1
#IBOutlet weak var itemNameLabelCell: UILabel!
#IBOutlet weak var itemDescLabelCell: UILabel!
#IBOutlet weak var itemPriceLabelCell: UILabel!
#IBOutlet weak var itemQuantityLabelCell: UILabel!
#IBOutlet weak var itemDecrementButton: UIButton!
#IBOutlet weak var itemIncrementButton: UIButton!
#IBOutlet weak var addToCartButton: UIButton!
weak var delegate: GondolaTableViewCellDelegate?
#IBAction func addToCartCellButton(_ sender: Any) {
delegate?.tableViewCellAddToCart(self)
//print("Neck, Angel Memory")
}
#IBAction func itemIncrementButtonCell(_ sender: Any) {
delegate?.tableViewCellIncrement(self)
//quantity = quantity+1
//itemQuantityLabelCell.text = "\(quantity)"
}
#IBAction func itemDecrementButtonCell(_ sender: Any) {
delegate?.tableViewCellDecrement(self)
// if quantity == 1 {
// //toastNeck(message: "Min. quantity should be 1")
// }else if quantity >= 2 {
// //quantity = quantity-1
// }
//itemQuantityLabelCell.text = "\(quantity)"
}
}
class AllItemViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, GondolaTableViewCellDelegate {
var tableViewCellQuantity: String = ""
#IBOutlet weak var allItemImageHeader: UIImageView!
#IBOutlet weak var allItemTableView: UITableView!
#IBOutlet weak var allItemLabel: UILabel!
#IBOutlet weak var visualEffect: UIVisualEffectView!
#IBOutlet weak var itemsTableView: UITableView!
#IBOutlet weak var itemDetailLabel: UILabel!
#IBOutlet weak var cartItemLabel: UILabel!
var storeItem = [StoreItem]()
var allItem = [ItemDetaill]()
var quantityArray: [Int] = []
var selectedIndex: Int!
var storeId: String = ""
var storeCatId: String = ""
var storeName: String = ""
var quantity = 1
override func viewDidLoad() {
super.viewDidLoad()
for i in 0 ..< 100 {
quantityArray.append(2)
}
allItemTableView.delegate = self
allItemTableView.dataSource = self
itemsTableView.delegate = self
itemsTableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return tableView === allItemTableView ? storeItem.count : allItem.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1 //storeItem.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 5
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UIView()
header.backgroundColor = UIColor.white
return header
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView === allItemTableView ? 56 : 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == allItemTableView {
let storeCell = allItemTableView.dequeueReusableCell(withIdentifier: "allItemCell", for: indexPath) as! AllItemTableViewCell
return storeCell
}else {
let itemCell = itemsTableView.dequeueReusableCell(withIdentifier: "itemTableCell", for: indexPath) as! ItemDetailTableViewCell
itemCell.itemNameLabelCell.text = allItem[indexPath.section].item_name
itemCell.itemDescLabelCell.text = allItem[indexPath.section].item_desc
itemCell.itemPriceLabelCell.text = "₹" + allItem[indexPath.section].item_net_price
itemCell.delegate = self
itemCell.addToCartButton.tag = indexPath.section
itemCell.addToCartButton.addTarget(self, action: #selector(addToCarts(_:)), for: .touchUpInside)
itemCell.itemIncrementButton.tag = indexPath.section
itemCell.itemIncrementButton.addTarget(self, action: #selector(increment(_:)), for: .touchUpInside)
itemCell.itemDecrementButton.tag = indexPath.section
itemCell.itemDecrementButton.addTarget(self, action: #selector(decrement(_:)), for: .touchUpInside)
return itemCell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedIndex = indexPath.section
if tableView == allItemTableView {
}else {
let itemCell = itemsTableView.cellForRow(at: indexPath)
print("Will Work")
}
}
#objc func increment(_ sender: UIButton) {
quantity = quantity + 1
tableViewCellQuantity = "\(quantity)"
//let newQuantity = quantityArray[sender.tag] + 1
//self.quantityArray.replaceSubrange(sender.tag, with: newQuantity)
itemsTableView.reloadData()
}
#objc func decrement(_ sender: UIButton) {
if quantity == 1 {
toastNeck(message: "Min. quantity should be 1")
}else if quantity >= 2 {
quantity = quantity - 1
}
tableViewCellQuantity = "\(quantity)"
itemsTableView.reloadData()
}
#objc func addToCarts(_ sender: UIButton) {
if sender.tag == 0 {
print(storeItem[sender.tag].item_name)
}
}
func tableViewCellAddToCart(_ sender: ItemDetailTableViewCell) {
guard let tappedIndexPath = itemsTableView.indexPath(for: sender) else {
return
}
print(allItem[tappedIndexPath.section].item_name)
}
func tableViewCellIncrement(_ sender: ItemDetailTableViewCell) {
guard let tappedIndexPath = itemsTableView.indexPath(for: sender) else {
return
}
print(allItem[tappedIndexPath.section].created_date)
quantity = quantity + 1
tableViewCellQuantity = "\(quantity)"
//let newQuantity = quantityArray[tappedIndexPath.section] + 1
//self.quantityArray.replaceSubrange(tappedIndexPath.count, with: <#T##Collection#>)
}
func tableViewCellDecrement(_ sender: ItemDetailTableViewCell) {
guard let tappedIndexPath = itemsTableView.indexPath(for: sender) else {
return
}
if quantity == 1 {
toastNeck(message: "Min. quantity should be 1")
}else if quantity >= 2 {
quantity = quantity - 1
}
tableViewCellQuantity = "\(quantity)"
itemsTableView.reloadData()
print(allItem[tappedIndexPath.section].id)
}
func tableViewCellQuantity(_ sender: ItemDetailTableViewCell) {
}
}
However I am able to detect the button clicks through protocols, but unable to update the UILabel.
Also I need to store the added items into data model class and have to be different values of different items, means each item should store diffrent quantities.
There is a similar question here but its not working.
Please let me know if anyone need any more details.
Try this :
#objc func increment(_ sender: UIButton) {
if let cell = sender.superview?.superview as? YourCellClass {
let indexPath = tbl_songsInfo.indexPath(for: cell)
//Do whatever you want
quantity = quantity + 1
tableViewCellQuantity = "\(quantity)"
//let newQuantity = quantityArray[sender.tag] + 1
//self.quantityArray.replaceSubrange(sender.tag, with: newQuantity)
itemsTableView.reloadData()
}
}
check out this link

Can't save data to MVC (Swift)

I can't save my data from textfield to MVC.
When I enter text and click on the button, the data is not added.
how can i fix it?
I delete viewDidLoad() with table.delegate = self, table.dataSource = self from this Question.
This is the ViewController:
class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var table: UITableView!
#IBOutlet weak var Text: UITextField!
var model = ViewModel()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.persons?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
let person = model.persons?[indexPath.row]
cell.Name?.text = person?.name
return cell
}
func textFieldEditing(_ sender: UITextField) {
model.input = sender.text
}
#IBAction func Add(_ sender: UIButton) {
if let name = model.input, name.count > 0 {
let person = Person()
person.name = name
model.addPerson(person)
model.input = nil
}
table.reloadData()
}
}
Model
class ViewModel {
var persons: [Person]?
var input: String?
func addPerson(_ person: Person) {
if persons == nil { persons = [] }
persons?.append(person)
}
}
class Person {
var name: String?
}
try this
// func textFieldEditing(_ sender: UITextField) {
// model.input = sender.text
// }
func textFieldDidEndEditing(_ textField: UITextField) {
model.input = textField.text
}
#IBAction func Add(_ sender: UIButton) {
self.view.endEditing(true)
if let name = model.input, name.count > 0 {
let person = Person()
person.name = name
model.addPerson(person)
model.input = nil
}
table.reloadData()
}

Update initialized Data in array with variable then pass array to next view controller

I'm having issues moving the data from the selected cells from the (service2viewcontroller) to the (confirmorderviewcontroller). I am trying to move the cell data (cells with a stepper.value above 0(var quantity > 0.0 (in Service2ViewController))), I was told to pass the array to the next view controller, to do so for a stepper value above 0 I would need to also send the indexpath.row for the rows with a quantity variable above 0 correct? I don't know how to do this if anyone can help I would greatly appreciate it. also the label is not updating when I use the stepper it stays at 0, can I place the quantity variable inside of the array? the total price label in the view controller continues to function and the data is sent to the (confirmorderviewcontroller) with no issues.
first TableView (data is input and forwarded)
class Service2ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var service2Total: UILabel!
#IBOutlet weak var service2TableView: UITableView!
// service data
var Wash: [Service2] = []
//stepper and price calculation
var quantity = Double()
var totalPrice : Double = 0.0
var priceList = [Int : Double]()
var totalProductPrice = [Int : Double]()
var label : Int!
override func viewDidLoad() {
super.viewDidLoad()
Wash = Options2()
if Int(quantity) > 0{
service2TableView.reloadData()
}
priceList[0] = 3.51//price list
priceList[1] = 5.51
service2Total.text = "$0.00"
}
// create data array
func Options2() -> [Service2]{
var washOptions: [Service2] = []
let option1 = Service2(titled: "Test", pricing: "$3.51", image: #imageLiteral(resourceName: "Wash&Fold"), description:"Testing the description box", quantity: Int(quantity))
let option2 = Service2(titled: "Test", pricing: "$5.51", image: #imageLiteral(resourceName: "Wash&Fold"), description: "Testing the description box", quantity: Int(quantity))
washOptions.append(option1)
washOptions.append(option2)
return washOptions
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Wash.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Wash1 = Wash[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Service2Cell", for: indexPath) as! Service2TableViewCell
cell.setService(Wash: Wash1)
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 133
}
#IBAction func stepperAcn(_ sender: UIStepper) {
//change label value with stepper
let cellPosition = sender.convert(CGPoint.zero, to: service2TableView)
let indPath : IndexPath = service2TableView.indexPathForRow(at: cellPosition)!
quantity = sender.value
let getCurrentProductPrice : Double = priceList[indPath.row]! * sender.value
totalPrice = gettingPriceLabel(indPath: indPath, getCurrentProductPrice: getCurrentProductPrice)
if totalPrice == 0{
service2Total.text = ("$0.00")
}
else{
service2Total.text = ("$")+String(totalPrice)
}
print("total price",totalPrice)
print("quantity double",quantity)
service2TableView.reloadData()
}
func gettingPriceLabel(indPath: IndexPath, getCurrentProductPrice : Double) -> Double
{
totalProductPrice[indPath.row] = getCurrentProductPrice
var totalCost : Double = 0.0
let valuesArr = Array(totalProductPrice.values)
for i in 0..<valuesArr.count
{
totalCost = totalCost + valuesArr[i]
}
return totalCost
}
// add function to collect (didSelectRowAt) and send selected data to cart and prepare for segue
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
// change sender to
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController: ConfirmorderViewController = segue.destination as! ConfirmorderViewController
if totalPrice > 0.00{
DestViewController.amount = totalPrice
}
}
}
service initializer
class Service2
{
var service2Title: String
var service2Image: UIImage
var Service2Pricing: String
var service2Description: String
var service2Quantity: Int
init(titled: String, pricing: String, image: UIImage, description: String, quantity: Int){
self.service2Title = titled
self.Service2Pricing = pricing
self.service2Image = image
self.service2Description = description
self.service2Quantity = quantity
}
}
Service 2 TableViewCell
class Service2TableViewCell: UITableViewCell {
#IBOutlet weak var service2Title: UILabel!
#IBOutlet weak var service2Stepper: UIStepper!
#IBOutlet weak var service2StepperLbl: UILabel!
#IBOutlet weak var service2Pricing: UILabel!
#IBOutlet weak var service2Image: UIImageView!
#IBOutlet weak var service2Description: UILabel!
func setService(Wash: Service2){
service2Image.image = Wash.service2Image
service2Pricing.text = Wash.Service2Pricing.description
service2Title.text = Wash.service2Title
service2Description.text = Wash.service2Description
service2StepperLbl.text = Wash.service2Quantity.description
}
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
}
}
Second TableView (receives data)
class ConfirmorderViewController: UIViewController{
#IBOutlet weak var Total: UILabel!
#IBOutlet weak var confirmOrderTableView: UITableView!
var titled = [String]()
var amount: String = ""
//var quantity = String()
var image1 = [UIImage]()
var Price = [Double]()
override func viewDidLoad() {
super.viewDidLoad()
Total.text = amount
confirmOrderTableView.reloadData()
}
}
extension ConfirmorderViewController: UITableViewDataSource, UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titled.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ConfirmOrderTableViewCell") as! ConfirmOrderTableViewCell
cell.coTitle?.text = titled[indexPath.row]
cell.coImg?.image = image1[indexPath.row]
//cell.coQuantity.text = quantity
cell.coPrice?.text = Price.description
return cell
}
}
I have tried here. I got list of row numbers having more than 0 order. I have it stored in whichRowToBeAdd. If user decreased to Zero, respective rows will removed from this array.
With the help of Singleton Class, we can store whatever we need to show in NextViewController
var whichRowToBeAdd = [Int]() // GLOBAL
#IBAction func stepperAcn(_ sender: UIStepper) {
//change label value with stepper
let cellPosition = sender.convert(CGPoint.zero, to: service2TableView)
let indPath : IndexPath = service2TableView.indexPathForRow(at: cellPosition)!
if Int(sender.value) == 0
{
if whichRowToBeAdd.contains(indPath.row)
{
whichRowToBeAdd.remove(at: whichRowToBeAdd.index(of: indPath.row)!)
}
else
{
}
}
else
{
if whichRowToBeAdd.contains(indPath.row)
{
}
else
{
whichRowToBeAdd.append(indPath.row)
}
}
//....
//..... Your Code in your answer
}
// After stepper Action, final click of Button, which moves to Next ViewController
#IBAction func goToConfirmOrder(_ sender: UIBarButtonItem) {
print("\n\n Val_ ", whichRowToBeAdd)
singleTon.sharedInstance.orderDict.removeAll()
for i in 0..<whichRowToBeAdd.count
{
let indPath = IndexPath(row: whichRowToBeAdd[i], section: 0)
let newCell = tblVw.cellForRow(at: indPath) as! Service2TableViewCell
print("qweqwe ",newCell.testLbl.text)
let name : String = newCell.service2Title.text!
let image : UIImage = newCell.service2Image.image
let quantity : Int = Int(newCell.service2StepperLbl.text!)!
getOrderOneByOne(productName: name, productImage: image, productQuantity: quantity)
if i == (whichRowToBeAdd.count - 1)
{
self.performSegue(withIdentifier: "confirmOrderVC", sender: nil)
}
}
}
func getOrderOneByOne(productName: String, productImage : UIImage, productQuantity: Int)
{
let createDict = ["productName" : productName, "productImage" : productImage, "productQuantity" : productQuantity] as [String : Any]
singleTon.sharedInstance.orderDict.append(createDict)
}
Singleton Class
class singleTon: NSObject {
static let sharedInstance = singleTon() // Singleton Instance
var orderDict = [[String : Any]]() // Dictionary Declaration
}
Next ViewController
class ConfirmOrderViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("\n\norderDict.coun ", singleTon.sharedInstance.orderDict)
}
}
With this, you can display datas in TableView in this ConfirmOrderViewController.

Cell is not selectable embed UItableView inside main View?

I have UITableView embed inside a main UIView. My problem is when I click on a cell to select items, it is not responding to the selection or triggering the segue.
Note: In attributes inspecter
is selection supposed to be set to single selection?
Update Note: the prepareForSegue function is not triggering or print "test".
import UIKit
import SwiftValidator
import CoreData
class EditNpFormViewController: UIViewController,UITextFieldDelegate, UIViewControllerTransitioningDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(EditNpFormViewController.dismissKeybored)))
self.npVisitViewTable.dataSource = self
self.npVisitViewTable.delegate = self
loadValidaValidationSettings()
loadUIObjectsSetting()
populateUIobjects()
}
func loadValidaValidationSettings() {
validator.styleTransformers(success:{ (validationRule) -> Void in
// clear error label
validationRule.errorLabel?.hidden = true
validationRule.errorLabel?.text = ""
if let textField = validationRule.field as? UITextField {
textField.layer.borderColor = UIColor.greenColor().CGColor
textField.layer.borderWidth = 0.5
}
}, error:{ (validationError) -> Void in
print("error")
validationError.errorLabel?.hidden = false
validationError.errorLabel?.text = validationError.errorMessage
if let textField = validationError.field as? UITextField {
textField.layer.borderColor = UIColor.redColor().CGColor
textField.layer.borderWidth = 1.0
}
})
validator.registerField(firstNameTextField, errorLabel:firstNameErrorLabel , rules: [RequiredRule(), AlphaRule()])
validator.registerField(lastNameTextField, errorLabel:lastNameErrorLabel , rules: [RequiredRule(), AlphaRule()])
validator.registerField(brnTextFieled, errorLabel:brnErrorLabel, rules: [RequiredRule(), AlphaNumericRule()])
}
func loadUIObjectsSetting(){
self.firstNameTextField.delegate = self
self.lastNameTextField.delegate = self
self.brnTextFieled.delegate = self
self.pickerLhsc.dataSource = self
self.pickerLhsc.delegate = self
self.pickerLhsc.tag = 0
self.ltchTextFieled.inputView = pickerLhsc
self.ltchTextFieled.delegate = self
self.ltchTextFieled.hidden = true
}
func populateUIobjects(){
self.firstNameTextField.text = selectedNpForm!.patientFirstName
self.lastNameTextField.text = selectedNpForm!.patientLastName
self.brnTextFieled.text = selectedNpForm!.brnNumber
self.ltchTextFieled.text = pickerDataLtch.filter { $0.uniqId == selectedNpForm!.ltch }.first?.hospital ?? ""
self.isPatientLtchResidentSwitch.setOn((selectedNpForm!.isPatientLtchResident == 0 ?false : true), animated: true)
self.ltchTextFieled.hidden = !(isPatientLtchResidentSwitch.on ? true : false)
reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - Methods
func dismissKeybored(){
firstNameTextField.resignFirstResponder()
lastNameTextField.resignFirstResponder()
brnTextFieled.resignFirstResponder()
ltchTextFieled.resignFirstResponder()
}
func textFieledShouldReturn(){
firstNameTextField.resignFirstResponder()
lastNameTextField.resignFirstResponder()
brnTextFieled.resignFirstResponder()
ltchTextFieled.resignFirstResponder()
}
func hideKeyboard(){
self.view.endEditing(true)
}
func validationSuccessful() {
print("Validation Success!")
}
func validationFailed(errors:[(Validatable, ValidationError)]) {
print("Validation FAILED!")
// turn the fields to red
for (field, error) in errors {
if let field = field as? UITextField {
field.layer.borderColor = UIColor.redColor().CGColor
field.layer.borderWidth = 1.0
}
error.errorLabel?.text = error.errorMessage // works if you added labels
error.errorLabel?.hidden = false
}
}
func reloadData(predicate: NSPredicate? = nil) {
if let selectedNpForm = selectedNpForm {
if let formVisits = selectedNpForm.visits?.allObjects {
npVisits = formVisits as! [NpVisit]
}
} else {
let fetchRequest = NSFetchRequest(entityName: "NpVisit")
fetchRequest.predicate = predicate
do {
if let results = try moc.executeFetchRequest(fetchRequest) as? [NpVisit] {
npVisits = results
}
} catch {
fatalError("There was an error fetching the list of devices!")
}
}
npVisitViewTable.reloadData()
}
//MARK: - #IBAction
#IBAction func EditBrn(sender: AnyObject) {
print("Validating...")
//validator.validate(self)
}
#IBAction func saveNpForm(sender: AnyObject) {
if let selectedNpFormId = moc.objectWithID(selectedNpForm!.objectID) as? NpForm{
selectedNpFormId.brnNumber = brnTextFieled.text
selectedNpFormId.patientFirstName = firstNameTextField.text
selectedNpFormId.patientLastName = lastNameTextField.text
selectedNpFormId.isPatientLtchResident = isPatientLtchResidentSwitch.on ? true : false
selectedNpFormId.ltch = hospitalUniqId
}
do {
try moc.save()
} catch let error as NSError {
print("Could not save \(error), \(error)")
}
}
#IBAction func dosePatientResideLtch(sender: AnyObject) {
self.ltchTextFieled.hidden = !(isPatientLtchResidentSwitch.on ? true : false)
}
// MARK: Validate single field
// Don't forget to use UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
validator.validateField(textField){ error in
if error == nil {
// Field validation was successful
} else {
// Validation error occurred
}
}
return true
}
//MARK: - Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "addNewNoVisit"){
if let distination = segue.destinationViewController as? MapViewController{
distination.clientNpForm._patientFirstName = firstNameTextField.text!
distination.clientNpForm._patientLastName = lastNameTextField.text!
distination.clientNpForm._brnNumber = brnTextFieled.text!
distination.clientNpForm._isPatientLtchResident = isPatientLtchResidentSwitch.on ? true : false
distination.clientNpForm._ltch = hospitalUniqId
distination.editNpFormMode = editNpFormMode
distination.selectedNpForm = selectedNpForm
}
}
if (segue.identifier == "sendNpVisitToVisitDetailSegue"){
print("test segue fired ")
}
}
//MARK: - #IBOutlet
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var brnTextFieled: UITextField!
#IBOutlet weak var npVisitViewTable: UITableView!
#IBOutlet weak var firstNameErrorLabel: UILabel!
#IBOutlet weak var lastNameErrorLabel: UILabel!
#IBOutlet weak var brnErrorLabel: UILabel!
#IBOutlet weak var isPatientLtchResidentSwitch: UISwitch!
#IBOutlet weak var ltchTextFieled: UITextField!
#IBOutlet weak var saveNpForm: UIButton!
//MARK: -VARIABLES
let validator = Validator()
var pickerLhsc = UIPickerView()
var editNpFormMode = FormMode.Edit
var selectedNpForm = NpForm?()
var npVisits = [NpVisit]()
var moc = DataController().managedObjectContext
var hospitalUniqId:Int = 0
var pickerDataLtch:[(uniqId:Int,hospital:String)] = [(229,"hospital 1"),
(230,"hospital 2"),
(231,"hospital 3")]
}
extension EditNpFormViewController:UIPickerViewDataSource,UIPickerViewDelegate {
// MARK, - Picker View
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
//return pickerDataLhsc.count
return pickerDataLtch.count
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int){
hospitalUniqId = pickerDataLtch[row].uniqId
ltchTextFieled.text = pickerDataLtch[row].hospital
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)-> String? {
return pickerDataLtch[row].hospital
}
}
extension EditNpFormViewController: UITableViewDelegate,UITableViewDataSource{
func tableView(npVisitViewTable: UITableView, numberOfRowsInSection section: Int) -> Int{
return npVisits.count
}
func tableView(npVisitViewTable: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell:UITableViewCell = npVisitViewTable.dequeueReusableCellWithIdentifier("visitCell")! as UITableViewCell
cell.textLabel?.text = "Visit #\(indexPath.row + 1)"
return cell
}
func tableView(npVisitViewTable: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(npVisitViewTable: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("selected row ")
}
}
In this answer I am making the assumption that didSelectRowAtIndexPath is firing.
In your didSelectRowAtIndexPath, you need to fire the segue that you created from the cell to the second view controller:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("selected row", indexPath)
performSegue(with: "segueIdentifier")
}
I'm not sure what version of Swift you are using, so you might need to make some slight changes.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//self.performSegue(withIdentifier: "sites", sender: self)
self.performSegue(withIdentifier: "CHANGE-TO-YOUT-SEGUE-ID", sender: self)
}
is the "hello" get printed? if so, call your segue from this point. Don't forget to connect your segue (from the top left square) in the story board as manual segue:
If func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) is not called at all, your problem is that the delegate of your UITableView is not set (or not correctly set). The delegate should be your EditNpFormViewController.
You can easily set the delegate of your UITableView instance by simply Control-dragging from the table to the controller that contains it (inside the Storyboard). The other simple way is by setting
tableView.delegate = self
You can just select the table inside the storyboard and drag the delegate from the right panel's circle to your controller:
If your delegate is set right, check the selection attribute of the cell itself:
If your table view is in editing mode, you need to set tableView.allowsSelectionDuringEditing = true

Resources