Table View Delegate method (didSelectRowAt) not called when row pressed - ios

I am trying to perform a segue when the user presses a certain cell/ row on a table View. I have implemented the delegate protocol
extension myVC : UITableViewDelegate
Here is my didSelectRow function
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "searchToOtherUser", sender: self)
}
There is also some extra stuff done in the previous function but when I put a breakpoint within the function, I can see that the app never goes into this function.
I have seen some of the answers previously mentioned on this topic (no user gesture is being used, and user interaction with the table view is enabled).
Does anyone have an idea on how I could fix this?
Thank you so much
Anthony

If the content is loading and the selection is enabled, then things to check are:
1) set delegate programmatically in swift
2) (optional) set the tableview delegate to File's Owner in case you added a tableview to your UIViewController in Storyboard instead of creating a UITableViewController (which does that automatically for you).
Check 1 - set delegate programmatically
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
...
}
Check 2 (only for TableView added to a UIViewController in Storyboard)
In the Storyboard through Interface Builder you should also link the tableview's delegate to the File's Owner:
**Check 2 - Step A) **
It can be that instead of having File's Owner explicitly stated on the left bar, it could be that you might have to do it this way:
Check 2 - Alternative Step A)
and then select delegate like this:
Check 2 - Step B)

Related

How does iOS call delegates and datasource methods?

For example, when we are creating tableview we need some datasource methods like
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messageArray.count
}
I don't call this anywhere. However, iOS does this instead of me and I wonder how iOS does this?
iOS search for a tableview, if it is available on the view then call delegates and datasource methods or it called when we declare uiTableView.delegate = self or uiTableView.datasource = self.
Another is these methods called before viewDidLoad?
Generally speaking, this is the setup for a class with a delegate:
class SimpleTableView {
var delegate: SimpleTableViewDelegate?
// ...
func renderCell(at row: Int) { // called whenever the table needs to render a cell
let cell = SimpleTableViewCell()
cell.frame.size.height = delegate?.tableView(self, cellHeightForRow: row)
// continue rendering cell
}
}
The protocol SimpleTableViewDelegate contains the delegate methods. It would look something like this:
protocol SimpleTableViewDelegate {
func tableView(_ tableView: SimpleTableView, cellHeightForRow: Int) -> CGFloat
}
So what we have here is a class, SimpleableView, that gets data from somewhere (the view controller). This is how the delegate comes into play:
class ViewController: UIViewController, SimpleTableViewDelegate {
var tableView = SimpleTableView()
override func viewDidLoad() {
tableView.delegate = self
}
func tableView(_ tableView: SimpleTableView, cellHeightForRow: Int) -> CGFloat {
return 44
}
}
This is essentially how a delegate works, and that is what the real tableView is doing. You set the tableView delegate and tableView calls the delegate methods to get information from you.
Hopefully this helps explain to you how the delegate works here, what calls it, and what's going on in general. If you need clarification, don't hesitate to ask!
So a quick way to look at this is separate these two things.
First lets look at delegate
https://developer.apple.com/documentation/uikit/uitableviewdelegate
The delegate provides a set of methods that you can include in your code that provides a callback for uitableview to execute certain protocol defined methods depending on whats happening within the tableView.
example func tableView(UITableView, heightForRowAt: IndexPath)
This example allows uitableview to ask you how should i display a certain cell at this current indexpath.
Next lets look at the datasource
https://developer.apple.com/documentation/uikit/uitableviewdatasource
Datasource works in a similar fashion as the delegate but provides a different set of methods that help you populate your table view.
example func numberOfSections(in: UITableView)
Apple's uitableview will call this method and ask the tableview how many sections should I display.
Ultimately, these are just protocols that allow the tableview to interact with your code and helping you display your table with your configuration!
tableView:numberOfRowsInSection is method of the UITableViewDatasource protocol. The methods of data source are called by method reloadData() of UITableView.
According to documentation of UITableView:
UITableView overrides the layoutSubviews() method of UIView so that it
calls reloadData() only when you create a new instance of UITableView
or when you assign a new data source. Reloading the table view clears
current state, including the current selection. However, if you
explicitly call reloadData(), it clears this state and any subsequent
direct or indirect call to layoutSubviews() does not trigger a reload.

Segue won't show the ViewController when pressed

I currently have a ViewController with prototype cells in a UITable View. The cells currently display content from a Firebase DB when loaded. What I would like to do is when a cell is pressed more information is shown from the Firebase DB. However, I currently cannot get the segue to push to the ViewController from the cell. What should I do so this would work?
Image of my Storyboard--
These are two pieces of code that will help. For swift:
#IBAction func showEntries(_ sender: Any) {
self.performSegue(withIdentifier: <sequeId>, sender: nil)
}
and a button with the action wrapping this.
For Objective C, you can perform the segue like so.
[self performSegueWithIdentifier:#"showEditor" sender:self];
Create the action by CTRL and dragging the button or cell into the corresponding code file, select action and name it.
It's hard to tell, but from the screenshot, it looks like the segue goes from controller to controller, rather than cell to controller. If you'd like to do it like this, then you need to give the segue an identifier (in the right panel of your screenshot) and then override the delegate method
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "yourIdentifier", sender: self)
}
OR (if you don't feel like going to all this trouble)...in the storyboard, drag the segue from the cell to the view controller you want to push, rather than from controller to controller.
For example,
Notice how when the segue is selected, only the cell is outlined in blue, rather than the entire view controller.
It's because cells are dynamic, so you can't assign an event handler from cell to uiviewcontroller. Instead you should make the segue inside your cellForRowAtIndexPath method and push it from there. If you want to see the segue inside the storyboard nevertheless, then you can also ctrl+drag from viewcontroller1 to viewcontroller2 to make a new segue. Then select the segue and give it a Storyboard id. After That you can call self.performSegue(withIdentifier: "yourIdentifier")
I actually found the solution to this. The issue was fairly simple actually. All I had to so was change the selection setting within the table view attributes from 'No Selection' to 'Single Selection'.

Protocol/delegate in Swift3 doesn't work

I have followed this tutorial to have delegate methods to update a value in my other class, but it does not even trigger it. Can you please tell me what i am doing wrong?
protocol myDelegate {
func report(info:String)
}
class TypeFilterViewController: UIViewController, XLFormRowDescriptorViewController,
UITableViewDataSource, UITableViewDelegate {
var delegate:myDelegate?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.delegate?.report("testValue")
self.navigationController?.popViewControllerAnimated(true)
}
}
So, after i select the row item, i dismissed pushed view and display previous class.
class SearchRefinementsTypeCell: XLFormBaseCell, XLFormBaseCellSeparator, myDelegate {
// Delegate method
func report(info: String) {
print("delegate: \(info)")
}
override func update() {
super.update()
let mc = TypeFilterViewController()
mc.delegate = self
self.headerLabel.text = //Value from TypeFilterViewController didSelectRow
}
Thank you for all kind of helps.
You clearly misunderstood the tutorial.
Delegate pattern is useful when you want to delegate from a cell to view controller. You're doing the opposite: sending event from a viewController to a cell, which is pointless, since your viewController already has access to it's tableView, which in it's turn operates with it's cells.
Also you shouldn't use any ViewControllers inside cell class because it breaks MVC pattern. You should think of UITableViewCell and pretty much every UIView as of powerless objects which cannot decide anything by themselves, but can only delegate events to other smart guys, which do the logic by themselves (view controllers).
Now about your case:
You have vc A and vc B, pushed over it. When a cell in B is pressed, you should send a callback to A, right? What you should do:
B has a delegate which implements some protocol
When A pushes B, it set's itself as a protocol: b.delegate = self
When a cell is selected in B, you call delegate's method, which is implemented in A and passes a string into it.
UI in A is updated.
Once again, cells must not know anything about any of your view controllers, they are just pawns. All logic should be handled between view controllers themselves.

student list on button click in swift

In my main.storyboard there has "all student" button. I need to open student list when "all student" button will be clicked.
Students are already saved in realm db. So far I've done below:-
Have dragged view controller from object library and have placed in empty space.
Have also dragged table view and table view cell inside view controller.
Created a modal segue from "all student" button to this view controller.
Have given cell identifier to "Cell" and segue identifier to "rList"
In vieController, I've made the following changes:-
Class vieController: UIvieController, UITextfieldDelegate
to below:
Class vieController: UIvieController, UITextfieldDelegate, UITableViewDelegate, UITableViewDatasource.
but getting below error in viewDidLoad:
fatal error: unexpectedlyfound nil while unwrapping an optional value
on below line:
table1.dataSource = self
Not getting how I'll achieve this student list. Any help would be appreciated.
Delete the line table1.dataSource = self
Then go to the Connections Inspectors of tableView from storyboard
after that drag the dataSource to your viewController
also make sure that your tableView outlet is connected properly.
I hope this help you
First, you should check to make sure that you have a proper table view outlet in your view controller. I show in my screenshot how the table view outlet is created.
You can then use
self.tableView.dataSource = self
in your viewDidLoad.
As far as getting the data to show, you can put your data into an array property in your view controller.
If the data is being loaded from the network, then the table view should be reloaded using tableView.reloadData() after the data has loaded.
The other pieces that you seem to be missing are the required data source methods for a UITableViewDataSource.
There are two functions that are required and they belong in your view controller.
I’ve provided minimal outlines below to get you started.
func tableView(tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
// The cell identifier is set in your storyboard.
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
// Do stuff like set values on labels in the cell.
cell.label.text = “text to display”
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
// Return the number of cells to be displayed.
return 10
}

cellForRowAtIndexPath not working properly

I have a tableView in my application and when a user taps on that cell, I need it to go to another view controller that gives more details about the cell they clicked on. When I try to get the cellForRowAtIndexPath by using
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
Nothing is printed to the console so I cant pass that data to another view controller through a segue without knowing that. Is there a reason this would not work?
I am getting the information though this array: var postsArray = [PFObject]() and the table is populated using return postsArray.count
Any help would be greatly appreciated. I may be overlooking it but I am not sure why this would not work as it has worked in other applications of mine.
I have imported delegates as well and have also called table.delegate = self to my viewDidLoad method.
class Profile: UIViewController, UITableViewDelegate, UITableViewDataSource
The full code can be found here: http://pastebin.com/26frZGpa
The line
tableView.delegate = self
as suggested in the very first comment is missing, that's the reason why the delegate method is not called. You can connect the delegate also in Interface Builder.
In your case to perform the segue it's more convenient to connect the segue to the table view cell rather than to the view controller.
The major benefit is that the table view cell is passed as the sender parameter in prepareForSegue and you can get the index path easily with
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let selectedIndexPath = tableView.indexPathForCell(sender as! UITableViewCell)!
}

Resources