How to parse text from each cell to another View Controller UITextField - swift

I have a class which is called InvoicesViewController "first image"
in that class there are cells that come from the API and each cell has a Label which represents a price of an item and a button near that price which segues you to PayViewController "second image"
and now i want that the UITextField in the PayViewController "second image" to be filled with the selected cell's label price.
I hope I am clear and someone guides me to the appropriate answer since i can't wrap my head around this one :)
This is my Code of the tableView :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
let data = notifications.Result![changeCustomerKey.DefaultsKeys.keyTwo].properties?[0].invoices
return data?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "invoicesCell", for: indexPath) as? invoicesModel else { return UITableViewCell() }
let currentNotifications = notifications.Result![changeCustomerKey.DefaultsKeys.keyTwo].properties?[0].invoices
let currentInvoices = currentNotifications![indexPath.row]
cell.mainPriceLabelInvoices.text = "€\(currentInvoices.priceWithVAT ?? 0.00)"
return cell
}

you can use navigation code for move to the next page and pass the value with navigation.
let storyBoard : UIStoryboard = UIStoryboard(name: "PayViewController", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "PayViewController") as! PayViewController
nextViewController.txtfield.text = value
self.present(nextViewController, animated:true, completion:nil)

At first, create a var in PayViewController like this
var price : Double = 0.0
Now in viewDidLoad() method write down the below code
self.textField.text = "€\(price)"
then, you have to write the following code in cellForRowAt func of tableView in InvoicesViewController
cell.editBtn.addTarget(self, action: #selector(buttonPayTapped(_:)), for: .touchUpInside)
Now add the following function
#objc func buttonPayTapped(_ sender:UIButton) {
guard let indexPath = tableView.indexPathForView(sender) else {return }
let vc = self.storyBoard?.instantiateViewController(withIdentifier: "PayViewController") as! AddCategoriesVC
let currentNotifications = notifications.Result![changeCustomerKey.DefaultsKeys.keyTwo].properties?[0].invoices
let currentInvoices = currentNotifications![indexPath.row]
// This is to transfer the selcted Data to Payment page
vc.price = currentInvoices.priceWithVAT ?? 0.00
self.present(vc, animated:true, completion:nil)
}
Add the following extension to get the exact indexPath
extension UITableView {
func indexPathForView(_ view: UIView) -> IndexPath? {
let center = view.center
let viewCenter = convert(center, from: view.superview)
let indexPath = indexPathForRow(at: viewCenter)
return indexPath
}
}

Related

UITapGestureRecognizer has no member tag

In this case i need my uiLabel clickable, so i add uiTapRecognizer. Then, i need to send the indexpath section to the tag so i can get the choosen section.
But when i try to get the sender.tag in tapFunction() there is error : UITapGestureRecognizer has no member tag
If i change the sender to uiButton -> func tapFunction(_ sender:uiButton) {
it doesn't print anything inside the function
Is there any workaround for this case (still using uilabel not change it to uibutton)?
Can i also send data when #selector tapfunciton(_: , data:"text")
and read it in tapFunction(data:String)? If this possible, can someone show it ?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "LoanCell", for: indexPath) as? LoanCell else {
return UITableViewCell()
}
let item = viewModel.itemsForRowAt(indexPath: indexPath)
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapFunction(_:)))
cell.syaratLabel.tag = indexPath.section
cell.isUserInteractionEnabled = true
cell.syaratLabel.addGestureRecognizer(tap)
return cell
}
#objc
func tapFunction(_ sender:UITapGestureRecognizer) {
print("successprint")
let item = viewModel.itemsForRowAt(indexPath: IndexPath(row: 0, section: sender.tag))
let viewController = DetilSandKViewController(messageSnK:item.prdAgreementDetail, titleSnK:item.nomorKontrak)
viewController.modalPresentationStyle = .overCurrentContext
viewController.modalTransitionStyle = .crossDissolve
present(viewController, animated: true, completion: nil)
}

How to implement a completion handler for Firebase update before table.reloadData is called in a different class?

Classes: ViewControllerTableViewCell and homepage ///the cell class is for cells on homepage
Problem: A button press triggers both 1) an IBAction that updated the firebase database (on ViewControllerTableViewCell) and 2) a model(on ViewControllerTableViewCell and homepage) that makes UI changes via table.reloadData.
The problem is the reloadData causes the wrong row to be recognized and updates in firebase for the wrong row. I checked this by removing reloadData and then the correct row is updated in firebase through the IBAction. Presumably this is because reloadData is executed before the database is done and then the row it returns are wrong. I am only having this problem with Xcode 13 btw.
class ViewControllerTableViewCell:
#IBAction func buttonPressed(_ sender: UIButton) {
...
**ref.child("users").child(self.postID).updateChildValues(updates)**
}
#objc func likeButtonTapped() {
// Calls the corresponding function of the delegate, which is set to the view controller.
delegate?.didTapLikeButton(on: row, didLike: !model.didLike)
}
override func awakeFromNib() {
like?.addTarget(self, action: #selector(likeButtonTapped), for: .touchUpInside)
}
func setup(with model: CellModel) {
}
class homepage
//in cellforRowAt {
cell.setup(with: model)
}
// in viewdidLoad {
setupmodels()
}
private func setupModels() {
....
models.append(model)
}
extension homepage: ViewControllerTableViewCellDelegate {
// Called from the cell's button action through the delegate property.
func didTapLikeButton(on row: Int, didLike: Bool) {
// Updates the corresponding cell's model so that it will update the cell when
// the table view reloads with the updated models.
models[row].didLike = didLike
**table.reloadData**
print("BBBBBBBBB")
}
//Added after first answer
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? ViewControllerTableViewCell {
let immy = cell.viewWithTag(1) as? UIImageView
let like = cell.viewWithTag(3) as? UIButton
let person: Userx = people[indexPath.row]
let text = person.Education
cell.lblName.text = person.Education
cell.lblName.text = text?.uppercased()
let person5 = colorArray[indexPath.row]
let person6 = colorArray1[indexPath.row]
let person7 = colorArray2[indexPath.row]
cell.lblName?.layer.masksToBounds = true
cell.lblName?.backgroundColor = person5
like?.backgroundColor = person6
immy?.backgroundColor = person7
cell.lblName.baselineAdjustment = .alignCenters
cell.postID = self.people[indexPath.row].postID
if let PhotoPosts = person.PhotoPosts {
let url = URL(string: PhotoPosts)
print(PhotoPosts, "sttdb")
immy?.sd_setImage(with: url)
}
cell.row = indexPath.row
// Assigns the delegate property to this view controller.
cell.delegate = self
cell.delegate2 = self
let model = models[indexPath.row]
let modell = modelss[indexPath.row]
like?.isUserInteractionEnabled = true
cell.setup(with: model)
cell.setup1(with: modell)
return cell
}
return UITableViewCell()
}
As suggested in comments,
on didTapLikeButton, update changes to your current model.
Instead of tableView.reloadData(), Reload the tableView row
tableView.reloadRows(at: [IndexPath(row: row, section: 0)], with: .automatic)
I am considering you have only 1 section in tableView, if not then get the section or the indexPath and pass it in the above code.

Select deselect the radio in uitableview section with array in ios swift

In tableview have different section.
Want to add the radio button for all the section.
Each section have individual select and deselect in tableview.
In first section choice1,[show in fig]
Selected cheese means cheese want to select, next if user click bacon means cheese automatically deselect.
[Here using radio button SSRadioButton class for click action. Create a radio button in tableview cell. how to write the button action for radio button. or suggest any new way].
Each radio button want individual select and deselect. The same process for all the section in tableview. how is possible help me. Thanks advance.
my code:
var radioControllerChoice : SSRadioButtonsController = SSRadioButtonsController()
var radioControllerDip : SSRadioButtonsController = SSRadioButtonsController()
func numberOfSections(in tableView: UITableView) -> Int {
return table_data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return table_data[section].menu_id.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:CustomiseTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Customise") as! CustomiseTableViewCell
cell.name.text?=table_data[indexPath.section].menu_name[indexPath.row]
print(table_data[indexPath.section].customize[indexPath.row])
switch indexPath.section {
case 2:
radioControllerChoice.addButton(cell.radioBtn)
radioControllerChoice.shouldLetDeSelect = false
case 3:
radioControllerDip.addButton(cell.radioBtn)
radioControllerDip.shouldLetDeSelect = false
switch Int(table_data[indexPath.section].customize[indexPath.row]) {
case 1:
cell.radioBtn.isHidden = false
default:
print("Invalid choose")
cell.radioBtn.addTarget(self, action: #selector(ViewController.didSelectButton), for: .touchUpInside)
cell.radioBtn.tag = indexPath.row
}
}
}
func didSelectButton(selectedButton: UIButton?)
{
/// need solution for button action help me..
}
You can use UIButton instead of SSRadioButton, and then you can change the image of button for checked and unchecked radio button.
Swift3.2:
CustomiseTableViewCell
import UIKit
protocol CustomTableViewCellDelegate {
func didToggleRadioButton(_ indexPath: IndexPath)
}
class CustomiseTableViewCell: UITableViewCell {
#IBOutlet weak var itemLabel: UILabel!
#IBOutlet weak var radioButton: UIButton!
var delegate: CustomTableViewCellDelegate?
func initCellItem() {
let deselectedImage = UIImage(named: "ic_radio_button_unchecked_white")?.withRenderingMode(.alwaysTemplate)
let selectedImage = UIImage(named: "ic_radio_button_checked_white")?.withRenderingMode(.alwaysTemplate)
radioButton.setImage(deselectedImage, for: .normal)
radioButton.setImage(selectedImage, for: .selected)
radioButton.addTarget(self, action: #selector(self.radioButtonTapped), for: .touchUpInside)
}
func radioButtonTapped(_ radioButton: UIButton) {
print("radio button tapped")
let isSelected = !self.radioButton.isSelected
self.radioButton.isSelected = isSelected
if isSelected {
deselectOtherButton()
}
let tableView = self.superview as! UITableView
let tappedCellIndexPath = tableView.indexPath(for: self)!
delegate?.didToggleRadioButton(tappedCellIndexPath)
}
func deselectOtherButton() {
let tableView = self.superview?.superview as! UITableView
let tappedCellIndexPath = tableView.indexPath(for: self)!
let indexPaths = tableView.indexPathsForVisibleRows
for indexPath in indexPaths! {
if indexPath.row != tappedCellIndexPath.row && indexPath.section == tappedCellIndexPath.section {
let cell = tableView.cellForRow(at: IndexPath(row: indexPath.row, section: indexPath.section)) as! CustomiseTableViewCell
cell.radioButton.isSelected = false
}
}
}
}
Call initCellItem method from UITableViewDataSource's delegate method:
// Your ViewController
let menuList = [ ["Cheese", "Bacon", "Egg"],
["Fanta", "Lift", "Coke"] ] // Inside your ViewController
var selectedElement = [Int : String]()
func didToggleRadioButton(_ indexPath: IndexPath) {
let section = indexPath.section
let data = menuList[section][indexPath.row]
if let previousItem = selectedElement[section] {
if previousItem == data {
selectedElement.removeValue(forKey: section)
return
}
}
selectedElement.updateValue(data, forKey: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:CustomiseTableViewCell =
tableView.dequeueReusableCell(withIdentifier: "Customise") as! CustomiseTableViewCell
let item = menuList[indexPath.section][indexPath.row]
cell.itemLabel.text = item
if item == selectedElement[indexPath.section] {
cell.radioButton.isSelected = true
} else {
cell.radioButton.isSelected = false
}
cell.initCellItem()
cell.delegate = self
// Your logic....
return cell
}
Alternate way:
You can use simple UIButton instead of any third party library (SSRadioButton) and use it like:
Set the UIButton's image in default state to - circle (as in the screenshot)
Set the UIButton's image in selected state to - filled circle
UIButton's action event can be captured in a normal way like you do in any other case.
Something like this:
Let me know if you want to follow this approach or need any kind of help regarding this.

sending customCell label text to destination view

I am stuck on this problem. I am downloading a json file from Firebase and successfully displaying in a TableView. That TableView has a custom cell with two labels. I have set up a segue link from the custom cell to a Detail ViewController. That works fine, but now I want to take the text content of the cell labels and send to a destination ViewController.
I have had no trouble doing this in the past, but am having trouble implementing this from the label.text in a custom cell.
I am using label tags (label1 and label2, although I may change that to the label names sometime).
The question is, how do I get the text contents from the two labels from the row selected and pass those to the DetailViewController? All my attempts so far have failed. Is there something I should be doing in the:
valueToPass = currentCell?.textLabel?.text
Here is the code:
struct postStruct {
let property : String!
let propType : String!
}
class TableViewController: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let property = snapshotValue!["property"] as? String
let propType = snapshotValue!["type"] as? String
self.posts.insert(postStruct(property: property, propType: propType), at: 0)
self.tableView.reloadData()
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].property
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].propType
// print(posts)
// cell.setcell(valueToPass.label1)
return cell!
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
var valueToPass:String!
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow;
let currentCell = tableView.cellForRow(at: indexPath!) as UITableViewCell!;
valueToPass = currentCell?.textLabel?.text
performSegue(withIdentifier: "detailSegue", sender: self)
}
Any help most welcome, in particular code examples. Many thanks in anticipation
Create a custom class for your tableCell, and attach outlets in the StoryBoard.
the cell creation in cellForRowAt becomes
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") As! MyCustomCell
cell.label1.text = posts[indexPath.row].property
cell.label2.text = posts[indexPath.row].propType
and then didSelectRowAtIndexPath becomes
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!) as! MyCustomCell
self.valueToPass = currentCell.label1?.text
performSegue(withIdentifier: "detailSegue", sender: self)
The final thing you need if to prepare for the segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "detailSegue" // you may have more than one segue, so you should check
{
let destinationController : DestinationViewControllerClass = segue.destination as! DestinationViewControllerClass
destinationController.valueToPass = self.valueToPass
}
}

Swift 3 Breaks Cell For Row At Index Path

This code was from a now inactive tutorial that helped me load in data to a table view. Since the tutorial was written in Swift 2.0, I believe that this was changed in Swift 3. I know that the override function itself was changed, which I handled. But now, it brings me a Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0) error.
Update: I have tried multiple things including creating a custom class for the cell. I still either get the same error I listed above, or a Thread 1: Signal SIGABRT error on the first line of my App Delegate file. Creating a breakpoint hasn't helped me because I know where the error is coming from.
import UIKit
import Firebase
import FirebaseDatabase
struct postStruct {
let title : String!
let message : String!
}
class LoggedInController: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
let message = snapshotValue!["message"] as? String
self.posts.insert(postStruct(title: title, message: message), at: 0)
self.tableView.reloadData()
})
post()
}
func post(){
let title = "Title"
let message = "Message"
let post : [String : AnyObject] = ["title" : title as AnyObject,
"message": message as AnyObject]
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").childByAutoId().setValue(post)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell!
}
}
Update 2: Here is the new code I used. It's not pretty and only gets the title.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell?.textLabel?.text = posts[indexPath.row].title
cell?.detailTextLabel?.text = posts[indexPath.row].message
return cell!
} else {
let label1 = cell?.viewWithTag(1) as? UILabel
label1?.text = posts[indexPath.row].title
let label2 = cell?.viewWithTag(2) as? UILabel
label2?.text = posts[indexPath.row].message
return cell!
}
}
Using dequeueReusableCell, you are accessing cell which doesn't exists. To make your code work change the below line:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
To
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
Ok this code let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") produces an optional called cell that may or may not contain a a valid instance of UITableViewCell. Optionals in Swift are a way to safeguard against nil values, you can read more about optionals here: Optionals
On the first run when your table view wants to load its data it calls all the required methods of your UITableViewDataSource. The first run is a critical one because there aren't any instances of the UITableViewCell the table view can dequeue yet. To solve your problem you have to do something similar to the code below:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
} else {
cell?.textLabel?.text = "" //reset value
cell?.detailTextLabel?.text = "" // resetValue
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
}
}
Code similar to the one above are usually used to programmatically add an instance of UITableViewCell. However, if you used interface builder to add a prototype cell use the let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) method to dequeue your cells in which case it does not return an optional and you do not need to do all the if / else blocks.
Something else I wanted to mention about your code is finding sub views buy their ID will not produce a very object oriented code and that maybe the source of your errors where the compiler can not find the sub views. The better way would be to use one of the built in instances of UITableViewCell such as .default or alliteratively you could subclass the said class and make your very own custom cells.
Hope this helped!
Try this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell
}
Edited
Make Sure you did these things
UITableViewController
In viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier:"catCell" )
let catNib : UINib = UINib.init(nibName: "TableViewCategoryCell", bundle: nil)
self.tableView.register(catNib, forCellReuseIdentifier: "TableViewCategoryCell")
In cellForRowAt indexPath
let cell : OPM_AlarmTableViewCategoryCell = tableView.dequeueReusableCell(withIdentifier:"OPM_AlarmTableViewCategoryCell" ) as! OPM_AlarmTableViewCategoryCell!
cell.categoryLabel?.text = "Some Text"
return cell
UITableviewCell.XIB
Hope u did these things
UITableviewCell
Make sure the dot appears so that the #IBOutlet is connected with the
xib label