Segue.destinationViewController is set to value of sourceViewController - ios

I'm learning about iOS as I write an application that uses a UITableViewController and Core Data to display a list of items, and another view controller that also uses Core Data to configure a variety of additional attributes that are not shown in the table view.
A button in the UITableViewController's navigation bar segues to another view that lets me set a variety of details. This is done using a storyboard "Show Detail" segue, and it works fine.
I want to use the accessory action button in a UITableViewCell to segue to the same detail view controller, so I created another "Show Detail" segue in the storyboard that connects the accessory detail button to the detail view controller (ie: the same kind of segue as the button in the navigation bar)
Confusingly, when I click the detail accessory button at run time, nothing happens, and prepareForSegue is never called.
The UITableView cell style is Subtitle, and I've configured it to have a Detail accessory action. However, the accessory button isn't displayed unless I specifically add it:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: Storyboard.reuseID)
let tone = toneTable[indexPath.row]
cell.textLabel!.text = tone.valueForKey("toneName") as? String
cell.detailTextLabel!.text = tone.valueForKey("toneDescription") as? String
cell.accessoryType = UITableViewCellAccessoryType.DetailButton
return cell
I finally gave up, and called prepareForSeque myself:
override func tableView(tableView: UITableView, accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath) {
let tone = toneTable[indexPath.row]
self.performSegueWithIdentifier("ShowToneDetail", sender: tone)
}
(I'm using the sender parameter as a convenient place to pass an NSManagedOject)
Now, prepareForSegue gets called, but if I put a breakpoint in prepareForSegue, I see that segue.destinationViewController points to the the source view controller, not the destination view controller. This is unfortunate, because I'd like to pass some values to the new instance of the destinationViewController.
Interestingly, the segue does correctly instantiate the destinationViewController, and passes control to it.
But, I don't understand what's going on. I don't know why I have to call prepareForSeque myself, and I don't know why the segue's destinationViewController isn't set correctly.
What am I doing wrong?
ps: is it just my perception, or is XCode less mature than other IDEs like Eclipse?

You're creating your cells in the wrong way. You should be using dequeueReusableCellWithIdentifier:forIndexPath: to dequeue a cell using the identifier you setup in the storyboard. By doing it the way you are, you're directly instantiating a cell that "knows" nothing about the cell in the storyboard where you added the detail disclosure button, or the segue you made.
I have no idea why the segue.destinationViewController would point to the source view controller. My guess is that it doesn't, and maybe you have your controller classes mixed up.

Related

Table View Cell Action Between View Controllers

I have an app that is two view controllers connected via a tab bar controller. The first view is a tableView cell and the second is several labels that are connected.
Currently my code works so that when I select a cell in the table view, it brings up the associated information from the second view controller. However, to get back to the first view controller, I currently have a back button.
How do I make it so the tab bar controller buttons don't disappear when the cell is tapped, so that I can quickly and more seamlessly jump between the two view controllers?
Relevant code for selecting a cell:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
x = indexPath.row
y = indexPath.row
z = indexPath.row
performSegue(withIdentifier: "seque", sender: self)
}
And then I call this in the viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
xLabel.text = wordList[x]
yLabel.text = wordDefinition[y]
zLabel.text = wordSnippet[z]
If I understand this correctly, you need to have your first VC embedded into a NavigationController and the Navigation Controller embedded into a TabBarController.
This way, when you drag a segue from your first VC to your second VC, the second VC will also be embedded into the same Navigation Controller.
And since the Navigation Controller is inside a TabBar Controller, the second VC will also be embedded into the same TabBar Controller.
You will end up with something like this:
As you can see, all VCs retain the TabBar and the Navigation Bar.
And you can do this by selecting the desired VC and then from Editor menu > Embed in.

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'.

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
}

How can hide on iPad an embedded secondary UITableViewController's DetailView on a UISplitViewController master using UIContainerView

First sorry for my english.
I have a UISplitViewController and i replaced the template master UITableViewController with an UIViewController put a UITableView and UIContainerView what contains a second static UITAbleViewController for settings one of this settings cell has another detail UITableViewController to change its value. on iPhone works well but on iPad with that splitviewcontroller this settings value table shows over on the splitviewcontroller detail view. its good too but i can't hide anymore. (On iPhone has a back button and just works well)
I couldn't find the solution.
My question is how can i hide that detail view to show the original detail view of the split view?
Here are my 3 pics from storyboard, the initial view and when the settings values are opens(that can't be hide n iPad)
Any advice would be nice. Thanks
Storyboard
Ipad screenshots
Finally i made an easy solution. Delete show detail storyboard segue on settings tableviewcontroller and define didSelectRowAtIndexPath for custom push
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//i want only the third row to perform an action
if indexPath.row == 2 {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let groupListViewController = mainStoryboard.instantiateViewControllerWithIdentifier("GroupListViewController") as! GroupListViewController
self.navigationController!.pushViewController(groupListViewController, animated: true)
}
}
This way i can push any view to the split view left or right side cos both have navigation controller. After this i defined the same function on the pushed tableviewcontroller fire some action and go back. It works like a charm on iPad and iPhone too.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.appDelegate.client.selectedGroupIndex = indexPath.row
//The main master viewcontroller of split view
let vehicleListViewController = self.navigationController?.viewControllers.first as! VehicleListViewController
//settingsviewcontroller that embedded in master viewcontroller
let vehicleListSettingsViewController = vehicleListViewController.childViewControllers.first as! VehicleListSettingsViewController
//call a custom function on embedded settings viewcontroller to change selected value
vehicleListSettingsViewController.changeGroup(indexPath.row)
//refresh splitviewcontroller's master tableview
vehicleListViewController.tableView.reloadData()
//Easy go back to masterview
self.navigationController?.popViewControllerAnimated(true)
}

Segue from a Custom Cell in UItableVew in IOS

I have created a custom cell and want to perform a segue to another ViewController by clicking on it.
I used didSelectRowAtIndexPath method and performed a segue but no result. The segue does not work!
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("toDetailViewSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexPath = tableView.indexPathForSelectedRow;
let cellname = tableView.cellForRowAtIndexPath(indexPath!) as! CardTableViewCell;
let DetailViewController = segue.destinationViewController
DetailViewController.title = cellname.textLabel?.text
}
Check the following items:
First, make sure that you established your segue. In your table view controller, control click on the yellow icon at the top of the table view controller's scene in the storyboard. Drag it to your destination view.
Second, make sure that the name of your Storyboard Segue matches the desired value (toDetailViewSegue).
In your storyboard, click on the segue that you created (either in the Document Outline or directly on the storyboard).
In the Utilities bar (right-side pane), go to the Attributes Inspector. There you will see Identifier of the Storyboard Segue. Make sure that it is the correct value.
Third, make sure that your custom table view cell has User Interaction Enabled checked.
In your storyboard, click on your custom cell.
Go to the Attributes Inspector. Look for the Interaction field within the View section. Make sure that it is checked.

Resources