How to get data from different table cell - swift

I have the following code which will trigger when the the didSelectRowAt is called. Which is basically when you click on any row.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if(indexPath.section == 0){
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!) as! addNameTableViewCell
print(currentCell.addNameTextField.text)
}
}
My problem is that I have four sections and in section zero is an button that when pressed I want to be able to return the data that is in section three.
let indexPath = tableView.indexPathForSelectedRow
So basically the problem is how to make this instead of the indexPath of the selected row, I want to be able to point it at a different indexPath.
EDIT:
let indexArray = tableView.indexPathsForVisibleRows
let currentCell = tableView.cellForRow(at: (indexArray?[1])!) as! addNameTableViewCell
I was able to solve it with the above but still be nice if a better way

Related

Crash: Attempted to dequeue multiple cells for the same index path, which is not allowed

I have tableview datasource func to build a cell from a factory method function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return OWTableViewOrganizer.instance.configureCell(at: indexPath)!
}
The factory method is here:
func configureCell(at indexPath: IndexPath) -> UITableViewCell? {
var cell = UITableViewCell()
switch indexPath.section {
case thisWorkoutSections.barbel.sectionNumber():
cell = barebellCell(indexPath: indexPath)
break
case thisWorkoutSections.lastWorkout.sectionNumber():
cell = lastWorkoutCell(indexPath: indexPath)
break
case thisWorkoutSections.personalRecord.sectionNumber():
cell = personalRecordCell(indexPath: indexPath)
break
case thisWorkoutSections.notes.sectionNumber():
break
default:
break
}
return cell
}
I have this code to build the cell:
func lastWorkoutCell(indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
if OWTableViewOrganizer.instance.lastWorkoutExerciseSets.count > 0 {
if indexPath.row < OWTableViewOrganizer.instance.lastWorkoutExerciseSets.count {
let logExerciseSet = OWTableViewOrganizer.instance.lastWorkoutExerciseSets[indexPath.row]
let setNumber = indexPath.row + 1
if let weight = logExerciseSet.weight?.doubleValue, let reps = logExerciseSet.reps?.intValue {
cell.setupCellWithData(setNumber: setNumber, weight: weight, reps: reps)
}
} else {
cell.setupCellWithData(setNumber: -1, weight: 0, reps: 0)
}
} else {
cell.setupCellWithData(setNumber: -1, weight: 0, reps: 0)
}
return cell
}
But time to time this line crashes for me:
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
With error:
Attempted to dequeue multiple cells for the same index path, which is not allowed. If you really need to dequeue more cells than the table view is requesting, use the -dequeueReusableCellWithIdentifier: method (without an index path)
I know code style and design is not ideal here, please skip this if you have comments.
I don't know where to look, I tried simply remove indexPath, but it looks does not help or bring even more issues:
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier()) as! WorkoutSetTableViewCell
I have one controller which presents another one at the top of it (like in Apple music) and I can swipe down to show bottom controller and swipe up to bring back top controller. I noticed in log that I have some presentation alert, not sure if this something I need to deal with to resolve the issue above but JFY info.
It seems like there are two table view trigger
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
and you only dequeue cell from 1 table view at
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
You should try to pass tableView from
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
to
lastWorkoutCell(indexPath: IndexPath)
(which will become lastWorkoutCell(indexPath: IndexPath, tableView: UITableView)) and dequeue cell from tableView

Getting a indexPath.row with a matching value

So, I have two Json requests from the same API with the difference, that one is from today and the other one from yesterday. I have them displayed in "MyCell" in my TableView and the result is this.
This is the code :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! CustomTableViewCell
let today = today[indexPath.row]
let yesterday = yesterday[indexPath.row]
let nameOfThe place = today.local
let salesToday = today.sales
let nameOfThePlaceYesterday = yesterday.local
let salesYesterday = yesterday.sales
}
So far, so good. Thats whats I wanted. The problem start when some places havent open yesterday( for example A and B). I get this:
Whats happening is, since there isnt the same "numberOfRowsInSection" for both days, it just populates cell in order but mismatching places. Question:
How do I get "indexPath.row" with a matching value of the other indexPath.row. In this case it would be a name of the place.
Thank you
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! CustomTableViewCell
let today = today[indexPath.row]
let nameOfThe place = today.local
let salesToday = today.sales
if let yesterday = yesterday[safe: indexPath.row] {
let nameOfThePlaceYesterday = yesterday.local
let salesYesterday = yesterday.sales
}
}

How to display a label on the last cell only?

I have a chat message table view with two cells to display, depending on whom sent the message.
I want the last cell to display the time, and only the last one. When I use tableView(:willDisplay cell:forRowAt indexPath:), the last cell doesn't show anything...
How can I display the time on that last cell?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if chatBubbles[indexPath.row].user == UserDefaultsService.shared.userID {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.senderCellIdentifier.rawValue, for: indexPath) as! SenderTVC
populateSenderChatBubble(into: cell, at: indexPath)
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.conversationCellIdentifier.rawValue, for: indexPath) as! ConversationTVC
populateConversationChatBubble(into: cell, at: indexPath)
return cell
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == chatBubbles.count - 1 {
// What to do in here to display the last cell time?
}
}
Here is the method that display the cell content:
func populateSenderChatBubble(into cell: SenderTVC, at indexPath: IndexPath) {
let bubble = chatBubbles[indexPath.row]
let isoDateString = bubble.date
let trimmedIsoString = isoDateString.replacingOccurrences(of: StaticLabel.dateOccurence.rawValue, with: StaticLabel.emptyString.rawValue, options: .regularExpression)
let dateAndTime = ISO8601DateFormatter().date(from: trimmedIsoString)
date = dateAndTime!.asString(style: .short)
time = dateAndTime!.asString()
if dateAndTime!.isGreaterThanDate(dateToCompare: Date()) {
dateToShow = "\(date!) \(time!)"
}
else {
dateToShow = "\(time!)"
}
cell.senderDateLabel.text = dateToShow
cell.senderConversationLabel.text = bubble.content
}
The cell doesn't know it's last unless you tell it, but the tableView does know who's last. With that in mind, I would add a boolean in your cell like this:
var isLastCell: Bool = false {
didSet {
// do stuff if it's the last cell
if isLastCell {
// configure for isLastCell
} else {
// configure it for !isLastCell
}
}
}
When your custom UITableViewCell class initializes, it'll be with isLastCell = false, so assume that in your configuration. Whenever the boolean is updated to true, the cell will update via the didSet.
Then, in your cellForRow method, test the indexPath to see if it's the last indexPath of the datasource, if so, cell.isLastCell = true and the didSet in the cell will trigger to do whatever adjustments you need to do.
Another thing you'll need to do with this implementation is use cellForRow to update isLastCell for not just the last cell, but the cells that aren't last, since cells are created and destroyed all the time and the last cell at one moment might not be the last cell in another.

Two Table Views in One VC

I want to display two (or more) table views from a single view controller. I mean display simultaneously, e.g., beside each other or one above the other. The only way I can think of doing it is with child view controllers. Is there a better or easier way?
Thanks for your comments.
Yes of course you can use like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if tableView == firstTableView
{
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell1", for: indexPath)
cell.textLabel?.text = "Section \(indexPath.section) Row \(indexPath.row)"
return cell
}
else if (tableView == secondTableView)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell2", for: indexPath)
cell.textLabel?.text = "Section \(indexPath.section) Row \(indexPath.row)"
return cell
}
else
{
return UITableViewCell()
}
}
Similar to other tableview delegate methods, you should add a condition for each table
If your use case is to have two individually scrolling table views then you can simply add two table views in the xib, assign datasource and delegates and call it a day.
If your use case is to display two types of information on a page I'd recommend using just one table view and handling what to display manually.
Let me know if you need any more help.
Use Switch Condition
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
switch tableView {
case firsttableView:
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.label1.text = "Zaid"
cell.label2.text = "Ahamd"
return cell
case secondTableView:
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondTableViewCell", for: indexPath) as! SecondTableViewCell
cell.labelText.text = "ZaidAfzalMughal"
return cell
default:
print("Something wrong")
}
return cell
}

How to change the state of the image in cell made in xib?

There is a TableView and a "Locked" image, how do I get alpha = 0 when I click cell 1 in cell 2? There is the cellForRowAt function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! TableViewCell
cell.commonInit("got_\(indexPath.item)", title: titleLessons[indexPath.item], sub: summary[indexPath.item], imageLock: imageZ[indexPath.item])
return cell
}
There is the didSelectRowAt function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if unlockedRows.contains(indexPath.row) {
let nextIndex = indexPath.row + 1
if nextIndex < pdfArr.count {
let vc = DetailLessonsVC()
let ce = TableViewCell()
vc.pdfTitle = pdfArr[indexPath.row]
vc.numberList = pdfArr[indexPath.row]
vc.linkList = link[indexPath.row]
unlockedRows.append(indexPath.row + 1)
self.navigationController?.pushViewController(vc, animated: true)
self.tableView.deselectRow(at: indexPath, animated: true)
}
print("no")
}
}
TableViewCell is xib's custom class.
You need to access the cell, and change image property, you can access the cell in didselect method with this:
let cell = tableView.cellForRowAtIndexPath(indexPath)
In your cell's custom class (TableViewCell) create an outlet for your image. If I understand correctly you want to edit cell located in the row number N+1 when user taps on the cell located in the row above, right?
If that's the case then all you have to do is get a reference to the next cell in didSelectRowAt. You can do just that this way:
var nextCellsIndexPath = indexPath
nextCellsIndexPath.row += 1
// Use 'if let' in order to make sure the cell at that index path exists
if let nexCell = tableView.cellForRow(at: nextCellsIndexPath) {
nextCell.lockedImage.alpha = 0
}
Since you didn't specify the number of sections in your table view, I assumed it has just one.