detecting clicked tableView - swift

Regardless of selection, I need to know the tableview involved with a mouse click. Consider
func tableViewSelectionDidChange(notification: NSNotification) {
self.selectedTableView = (notification.object as! NSTableView)
switch selectedTableView {
case oneTableView?:
print("one")
break
case twoTableView?:
print("two")
break
default:
print("wtf \(selectedTableView)")
}
}
table/view 'two' is a detail of 'one'. Selecting a row in 'one' alters the content for tableview 'two' (header -> detail). But if the user clicked a row already selected, no notification as the selection did not change. Basi I just need to know the last tableview / column clicked.
Is mouseDown approach better (way more difficult) but I do not see objective-c or 'UI' equivalent delegate methods in the AppKit -> NSTableView -> NSTableView for column or row selection methods?

What you should do is, within this UITableViewDelegate Function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let tableOne = tableView as? TableOne {// do code here to other table}
else if let tableTwo = tableView as? TableTwo {//do code here to other table}
}

Well, on osx in the current AppKit (8.2.1) state on Sierra this is not doable.
My gui is using a single action control for a set of header/detail tableViews and I needed to know which was in effect, so I'm to mandating an empty selection in the detail table view to indicate the header view selection is to be used.
But I would like to know why osx swift doesn't have a comparable delegate method set that ios or objective-c have?

Related

How to get didselectrowat from a custom cell with textboxes?

I have a dynamic tableview with 3(cell1,cell2,cell3) custom cells, which gets reused anywhere from 0 times up to 9 times. (Maximum cells in the tableview will be 27 cells).
Each of those 3 custom cells have 3 text boxes each, and in addition the second cell has 2 buttons to select gender and 3rd custom cell has a drop down menu, which has values of whatever typed in the first textbox of cell1 cells.
Now the issue is that, textbox takes the touch input from user (as it should) and didselectrowat never gets called and therefore i am not getting indexPath.
But i need the indexPath, so that i can insert user details from each of those cells into an array.
(anArray.insert("", at: indexPath)
Since i am not getting indexPath, everything fails. How can i get the indexPath and get the touch on to the textbox?
I am thinking of something like a function that takes the touch ,gets the indexPath and then passes the control to textbox.
Things i have tried.
I disabled the textboxes before user touches the cell (and makes textboxes disabled once user deselects the cell, so cell takes the touch. Once didselectrowat gets called, make the textbox active again and make
textbox.becomeFirstResponder()
But somehow , the textbox never becomes the first responder even though breakpoint shows the control going through it and the textbox becomes active. But no keyboard popsup, if i touch the cell again, same process happens.
What seems to be the issue here? I saw another post on the same topic, i tried it but unfortunately that doesnt work and it was for a static tableview.
Also is there a good way to do this? Other than making the user click on the cell twice / clicking outside the textbox..
You can set your custom cell as delegate for UITextField and use a callback for editing begins/ends as below,
class MyCustomCell: UITableViewCell, UITextFieldDelegate {
public var editCallback: (() -> Void)?
/// Set 'textField.delegate = self' on initialization.
func textFieldDidBeginEditing(_ textField: UITextField) {
self.editCallback?()
}
}
And use the callback in cellForRowAt as,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = MyCustomCell()
cell.editCallback = { [weak self] in
print(indexPath)
}
return cell
}
you can try this
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
//your code here
}

Swift: How to instantly reload data in a UITableViewController?

I have a number of entries (cells) in a UITableView in Swift which each represent a "song" that each user can select. The titles of the songs that have not yet been completed are represented by question marks and the others are displayed normally. The songs completed by the user are stored in a firebase database which is immediately read at the beginning of the UITableViewController lifecycle and stored in a global dictionary I called temp_dict.
The dictionary temp_dict is of the form
Key = "02": Value = "Complete",
Key = "03": Value = "Complete",
etc.
The problem is that the loading of the data into this Dictionary does not happen immediately and the initial call of the following "loading the cells" function:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
occurs before I have the information from the firebase to decide which ones have been completed or not.
I am now in a strange situation where the question marks will only appear after I have scrolled down to the bottom (there are around 30 cells) then scroll back up again. I believe this occurs because each cell is removed and added again when it is removed and reappears on the screen
What I've tried: I've tried using self.tableView.reloadData() at various stages but it does nothing for some reason.
class MainTableViewController: UITableViewController {
...
override func tableView(_ tableView: UITableView, cellForRowAt
indexPath: IndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath)
myCell.textLabel?.text = songs[indexPath.row].title
myCell.detailTextLabel?.text = songs[indexPath.row].artist
if (self.temp_dict[String(indexPath.row+1)] != "Complete") {
myCell.textLabel?.text = question_marks(s :
songs[indexPath.row].title)
myCell.detailTextLabel?.text = question_marks(s :
songs[indexPath.row].artist)
}
num_times_called = num_times_called + 1
return myCell
}
...
}
The function question_marks() just takes a string and replaces every character with a question mark to signify that the level has not been completed and so is hidden.
** songs is an array of song objects which have attributes of title, artist, song number etc.
Results:
Right now, I am greeted with all cells being entirely question marks when I start up this viewcontroller. When I scroll to the bottom and scroll back up, the songs that have been completed are now suddenly displayed as no longer question marks (which is what I want but I want this to happen immediately).
Summary:
I need a way to automatically reload all the cells on a uitableview immediately following the occurence of a particular event.
Thanks for any help.
Mr.P's answer is almost correct. I suggest to reload tableview on main thread:
var temp_dict: [String: String] {
didSet {
DispatchQueue.main.async {
tableView.reloadData()
}
}
}
Add a property observer to your temp_dict object so that it will reload the table view automatically when it is updated
var temp_dict: [String: String] {
didSet {
tableView.reloadData()
}
}

Errors when changing from UITableViewController to UITableView

I'm trying to embed a Table View in a regular View Controller because I want some other Views in the View Controller besides just the Table View. I had a Table View Controller with some methods that I was overriding. I copied the code for the Table View Controller, pasted it into a Table View .swift file, and removed the "override" before each method as the methods weren't inherent to the Table View class. Unfortunately I'm still getting errors in a few lines of the code:
super.viewDidLoad()
"Value of type 'UITableView' has no member 'viewDidLoad'"
tableView.rowHeight = UITableViewAutomaticDimension
"Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'"
tableView.estimatedRowHeight = 60.0
"Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'"
super.didReceiveMemoryWarning()
"Value of type 'UITableView' has no member 'didReceiveMemoryWarning'"
tableView.insertRows(at: [indexPath], with: .automatic)
"Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'"
What do I need to do to those lines of code to make my program run? It fails to build if I leave the code as it is, and if I put two slashes in front of those lines of code, it runs but just creates a black screen. Any help would be greatly appreciated! Thanks!
import UIKit
class TaskListTableView: UITableView {
var tasks:[Task] = taskData
func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
}
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
#IBAction func cancelToLoLFirstTableViewController(_ segue:UIStoryboardSegue) {
}
#IBAction func saveAddTask(_ segue:UIStoryboardSegue) {
if let AddTaskTableViewController = segue.source as? AddTaskTableViewController {
if let task = AddTaskTableViewController.task {
tasks.append(task)
let indexPath = IndexPath(row: tasks.count-1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
as! TaskCell
let task = tasks[indexPath.row] as Task
cell.task = task
return cell
}
}
I think you are confused about what the UITableView and UITableViewController classes do.
A UITableView class is the class that draws the table view component you see on your screen, updates it when necessary and interprets your taps and scrolls into something that makes sense in terms of a table. UITableView extends UIView.
The UITableViewController class is designed to manage a UITableView instance, providing data to display and responding to the actions that it generates. It is an extension of the UIViewController class.
UIView and UIViewController are completely different things and perform completely different functions. You cannot cut and paste code from one to the other because they won't understand it.
So my first recommendation is to hit the books. Read up on what UIView and UIViewController's do to get an understanding of their place in the iOS universe and how they relate to each other. Then look at UITableView and UITableViewController.
Secondly, as to your problem of wanting to have a screen with a table view as well as other components. There are multiple ways to do this and the best solution will vary depending on the complexity of the UI you are trying to build and the data and code behind it.
Once you've got your head around how views and controllers work. I would start by building a simple screen with several simple components on it and a single controller behind it. ie. A class you have written that extends UIViewController.
When your happy with this, you have two choices that I typically see:
You can add a UITableView UI component and set your UITableViewController as it's dataSource <UITableViewDataSource> and delegate <UITableViewDelegate>. Then add in the various methods from these protocols to define the data to display and how your controller will respond to your actions on the table view.
A more complex choice you should look at if #1 gets too messy. This choice can result in cleaner code. Instead of adding the UITableView UI component, you add a UIContainerView UI component. UIContainerViews are designed to link to a seperate controller and view. Effectively this means you have two controllers. One for the general UI components and one for the table view.
This is all going to depend on exactly what you are trying to do. But first you need to do some reading.

How to display item from array based on didSelectRowatIndexPath position?

I am coding an app which has a UITableView. I currently have a segue set up set up for the cells in the table as such:
var selectedRow = Int() //global variable so it can be used in both VCs
import UIKit
class TableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "rowSelected", sender: Any?.self)
selectedRow = indexPath.row
}
}
The segue works fine. However, in the swift file that controls the viewController (only being used to change the text of a label) does not work appropriately. Here is the code from that VC:
override func viewDidLoad() {
super.viewDidLoad()
firstLabel.text = infoArray[selectedRow]
print(selectedRow)
}
The infoArray is set up correctly, but the label is not always change to the correct text... printing selectedRow returns inconsistent numbers... if I hit the first cell it will return 0 sometimes, but it also returns 1, 3, 2, etc... It seems random and isn't correctly returning the current int (and therefore the label text isn't set correctly). Why is this?
What you're doing is not the way to pass information from one view controller to another. To pass information, pass the information. Instead of dropping the information in a global, implement prepare(for:sender:), where you can get the segue's destination view controller as it prepares, and set a property of the destination view controller.

How to append a cell to a tableview using iOS 9?

I am using Xcode 7.3 with iOS 9 and Swift. I would like a user to be able to enter an integer into a textfield, tap a button, and then have the integer display in a tableview on the same screen. I would like the user to be able to create a list of integers doing this.
I have my textfield, button, and tableview created. What's the easiest way to code this function?
I am guessing the you know how to use the standard table view, so that I don't have to post irrelevant code?
Try this.....
Use beginUpdates and endUpdates for insert new cell when button clicked..
First of all append data in your tableview array, let's say the array containing the content for your table view is named Yourarray
Yourarray.push(0815) // some integer, which you will grap from the input
Then upate your table and insert new row
// Update Table Data
tblname.beginUpdates()
tblname.insertRowsAtIndexPaths([
NSIndexPath(forRow: Yourarray.count-1, inSection: 0)
], withRowAnimation: .Automatic)
tblname.endUpdates()
You can see the line of code with Yourarray.count-1. There you can write any integer in which line you want to append the new cell.
If you are using a tableview you should be using an array to populate it with the tableview, I hope you are doing that.
Edit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
...
}
firstly you adopt your class from UITableViewDelegate and UITableViewDataSource .
Then you add these functions inside your class:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0 // how many tableview cells you want to display
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell // "cell" is the identifier in this case, change that in your storyboard
cell.textLabel?.text = "Your value for the tableview"
return cell
}
Inside the viewDidLoad you have to add this in order to hook it up:
self.zipTable.delegate = self
self.zipTable.dataSource = self