How to pass data between UITableViews in NavigationController? - ios

In my first tableViewController has navigationViewController.push(myNextController, animated: true) and I want to segue to another TableViewController. What I am trying to figure out for hours is that when I select a row in my first tableViewController, I want to move to the next tableview. Right now, when I select a row, my next tableVIew has the same data. I want each cell to have differently saved cells
Second table view controller
The title is the navigation title and the myArray is an array:
// globally declared
var dataArray = [String]()
var myArray = [String]()
// this function is in my second table view controller, viewDidLoad()
func data(){
myArray = UserDefaults.standard.stringArray(forKey: "Key")!
dataArray = myArray
}
The dataArray is:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
if let getData = UserDefaults.standard.stringArray(forKey:"key") {
cell.textLabel?.text = getData[indexPath.row]
}
tableView.reloadData()
return cell
}
first table view controller
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
cell.backgroundColor = UIColorUtil.rgb(rgbValue: 0xFFFFF9)
let getData = UserDefaults.standard.stringArray(forKey: "category")!
let nextViewController = TableView()
nextViewController._titile = getData[indexPath.row]
// so I access myArray from second table view controller because I want to
//get data of each selected cell. But this is a problem.
nextViewController.myArray = getData
self.navigationController?.pushViewController(nextViewController, animated:true)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
if let getData = UserDefaults.standard.stringArray(forKey:"category") {
cell.textLabel?.text = getData[indexPath.row]
}
return cell
}
Why do they have the same cells? How am I able to accomplish this without using a storyboard? I want to programmatically write code. By the way, I am using UITabBar as well. Thanks!

Related

unable to customize tableView for side menu in swift

I want to add spacing between rows and set the header
here my code is -
#IBOutlet weak var sideMenu: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TownTalkTableViewCell
cell.logo.setImage(arr[indexPath.row]["icon"] as? UIImage, for: .normal)
cell.grupName.text = array[indexPath.row]["groupname"] as? String
return cell
First Add tableview Delegate and Data Source for both tableview in storyboard by taping control+draging into viewcontroller
Then use the same delegate function to access sidemenu tableview.
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var sideMenu: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableview == sideMenu{
return 2
}else{
//this is for tableView
return 3
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableview == sideMenu{
//use slide menu tableview cell
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TownTalkTableViewCell
cell.grupImage.image = array[indexPath.row]["groupImage"] as? UIImage
cell.grupName.text = array[indexPath.row]["groupname"] as? String
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TownTalkTableViewCell
cell.grupImage.image = array[indexPath.row]["groupImage"] as? UIImage
cell.grupName.text = array[indexPath.row]["groupname"] as? String
return cell
}
}
2 ways.
make the view controller data source & delegate for both the tableviews & in the methods add the below check.
if tableview === self.tableview {
//its for table view
return ...
}
// else its for side menu
return ...
Create a separate class (Call it SideMenuTableViewHelper or something) for SideMenu tableView datasource & delegate.
First one is simpler, 2nd one is cleaner for datasource, messier for handling delegate (did select row) methods as they will most likely be triggering code in view controller (which can be done via View controller acting as custom delegate to the SideMenuTableViewHelper). For a beginner, I reckon go with (1).

How to get JSON id with button in tableview cell in swift4

I'm using tableView cell with button name of delete and I want to delete my JSON data from tableView cell I need to so That JSON ID to delete the JSON data from my Tableview. I'm using to get the JSON ID for that indexPath in didSelect row function. but the problem is I can't get JSON Id from that indexPath without pressing the row.
var selectedList: JSONList?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedList = JSONList[indexPath.row]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableviewCell
cell?.Numbers.text = JSONList[indexPath.row].Number
cell?.Trash.addTarget(self, action: #selector(Deleting), for: .touchUpInside)
cell?.selectionStyle = .none
return cell!
}
//here is my delete function calling
func Deleting() {
let selectedListObj = selectedList
print(selectedListObj!.id)
}
First of all set a tag to the button which it will be in your case the
row of the IndexPath, add this code in cellForRowAt:
cell?.Trash.addTarget(self, action: #selector(deleting(_:)), for:
.touchUpInside)
cell?.Trash.tag = indexPath.row
You need to modify the deleting() function to be #objc since selectors
after swift 3+ are a must to add that and add the button as param into it:
#objc private func deleting(_ button:UIButton){
// here you got the object
let selectedObject = JSONList[button.tag]
}
use closure to get the tapped buttons cells indexpath.
update the table view cell with ibaction and call the closure whenever tapping on trash button.
class FakeTableCell: UITableViewCell{
var selectedCell: ((UITableViewCell) -> ())?
#IBAction func trashButtonTapped(){
selectedCell?(self)
}
}
then we can get the indexpath of the cell in cell for row for indexpath as follows
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = FakeTableCell()
cell.selectedCell = { selectedCell in
if let ip = tableView.indexPathForRow(at: selectedCell.center){
self.deleteData(with: ip.row)
}
}
return cell
}
func deleteData(with row: Int){
// get the object by JSONList[row]
let item = JSONList[row]
// perform deletion
}

Adding UIButton to detailTextLabel/right side of UITableView

I'm quite new to Swift and I would like to know what is the easiest and simplest way for me to add in 10 buttons to 10 of my cell rows in my TableViewController.
P.S: It would be nice if the 10 buttons perform differently instead of duplicate.
import UIKit
import FirebaseDatabase
var ref: DatabaseReference?
var databaseHandle: DatabaseHandle?
var postData = [String]()
class TableViewController5: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference() //set the firebase reference
// Retrieve the post and listen for changes
databaseHandle = ref?.child("Posts3").observe(.value, with: { (snapshot) in
postData.removeAll()
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
postData.append(key)
}
self.tableView.reloadData()
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.font = UIFont.init(name: "Helvetica", size: 23)
cell.textLabel?.text = postData[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 80
}
}
From what I can understand, you should use prototype cell and add an IBAction in the cell and in that cell you should perform the segue and pass whatever data you need to customise the page you load.
In your tableView(_:cellForRowAt:) method, you can set a tag for the button.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? prototypeCell
cell.voteButton.tag = indexPath.row
return cell
}
Then in your cell's class, in the IBAction I mentioned earlier, check for the tag and set the data to pass accordingly.
Then in your prepareForSegue:sender: method, just pass the data you want to pass to the next view controller and all should work fine.
Check if it helps You
//Common cell Variable
var cell = UITableViewCell()
//UIButton commonly Declared
var acceptRequest = UIButton()
var declineRequest = UIButton()
My TableView Cell contains two button as shown Accept & Decline
In my tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) I added Handlers for button
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Cell for dequeuing
cell = self.RequestListTableView.dequeueReusableCell(withIdentifier: "Cell")!
//Used Tags here
//You can Make use of TableViewCell class here and Access Buttons from there
acceptRequest = cell.viewWithTag(4) as! UIButton
//Adding action Handlers for UIbuttons
self.acceptRequest.addTarget(self, action: #selector(RequestListView.AcceptRequest(sender:)), for: .touchUpInside)
return cell
}
my Button handler
func AcceptRequest (sender: UIButton) {
//Dequeue cell with identifier can be ignored
cell = self.RequestListTableView.dequeueReusableCell(withIdentifier: "Cell")!
//Get button position from TableView : Required
let buttonPosition : CGPoint = sender.convert(CGPoint.zero, to: self.RequestListTableView)
//Get index Path of selected Cell from TableView
//Returns Table Cell index same as didSelect
let indexPath : IndexPath = self.RequestListTableView.indexPathForRow(at: buttonPosition)!
//Can be used if you need to update a view
cell = self.RequestListTableView.cellForRow(at: indexPath)!
//Now time to access using index Path
cell.textLabel.text = array[indexPath.row] //Example
}
Can use this Procedure for even single Button or for multiple buttons too
In case if you have more than one button in one cell, this will help you

IndexPath in tablew view cell returned is wrong on click of a label in a UITableView

I have a label inside a table view cell.
On click of the label I want to segue to another view controller after retrieving the correct indexPath.
I have added a gestureRecognizer to the label. On click of the label it returns the wrong indexPath , it does not return the index Path of the cell in which the label is.
How can I solve this problem . Any help will be appreciated. Thank you
Following is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as! TableCell
cell.name.text = feeds[indexPath.row].name
nameClicked()
return cell
}
func nameClicked(){
cell.name.isUserInteractionEnabled = true
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(TrendViewController.handleTap(gestureRecognizer:)))
cell.name.addGestureRecognizer(gestureRecognizer)
}
func handleTap(gestureRecognizer: UIGestureRecognizer) {
var touchPoint = cell.name.convert(CGPoint.zero, to: self.tableView)
var clickedLabelIndexPath = tableView.indexPathForRow(at: touchPoint)!
nameFromView = feeds[clickedLabelIndexPath.row].name
print("IndexPath at touch",clickedLabelIndexPath)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "profile") as! ProfileViewController
vc.clickedLabelIndexPath = clickedLabelIndexPath
vc.nameFromView = feeds[clickedLabelIndexPath.row].name
self.navigationController?.pushViewController(vc, animated: true)
}
You have declare cell as instance property in your class,so you are adding gesture to the same cell's label. So create new cell using dequeueReusableCell and changed your method nameClicked by adding argument of type cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//create new cell
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as! TableCell
cell.name.text = feeds[indexPath.row].name
nameClicked(cell)
return cell
}
func nameClicked(_ cell: TableCell){
cell.name.isUserInteractionEnabled = true
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(TrendViewController.handleTap(gestureRecognizer:)))
cell.name.addGestureRecognizer(gestureRecognizer)
}
Now change your handleTap method like this to get the correct indexPath.
func handleTap(_ gestureRecognizer: UIGestureRecognizer) {
let point = self.tableView.convert(CGPoint.zero, from: gestureRecognizer.view!)
if let indexPath = self. tableView.indexPathForRow(at: point) {
print("\(indexPath.section) \(indexPath.row)")
//Add your code here
}
}
Note: If your cell having only single cell then it is batter if you use didSelectRowAt method instead of adding gesture to label.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
}
Maybe you should make condition for check if cell is touched ?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as! TableCell
if cell.isTouched {
cell.setTouched
}
else {
cell.setNoTouched
}
return cell
}

"Generate" labels from data swift

I have
["06:58"]
["07:13", "07:38", "07:53"]
["08:13", "08:38", "08:53"]
["09:13", "09:33", "09:53"]
and I want to show it in tableView as in picture:
every element - it's UILabel, I created class TimeViewCell: UITableViewCell where have property var labels = [UILabel]() but I don't know how to push data from my array in my function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTime", for: indexPath) as! TimeViewCell
let showHour = self.infoWripper.sorted(by: { $0.hour < $1.hour })
cell.labelTime.text = showHour[indexPath.row].showHour()
for data in showHour {
print(data.showFullTime()) //here you see my example of data in console
}
return cell
}
I would add a UIStackView to your UITableViewCell. You can add the labels with the text to the UIStackView.
I wrapped your data into an array.
let tableViewData = [["06:58"],
["07:13", "07:38", "07:53"],
["08:13", "08:38", "08:53"],
["09:13", "09:33", "09:53"]]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTime", for: indexPath) as! TimeViewCell
cell.configure(data: tableViewData[indexPath.row])
return cell
}
Then, in for your TimeViewCell, you have to add your UIStackView IBOulet (or add it programmatically) and the configure method.
class TimeViewCell: UITableViewCell {
#IBOutlet var labelStackView: UIStackView!
func configure(data: Array<String>) {
for time in data {
let timeLabel = UILabel()
timeLabel.text = time
labelStackView.addArrangedSubview(label)
}
}
}

Resources