I have a table. When I click on the cell segue should be performed. I try to use prepareForSegue and performSegueWithIdentifier, but without any result.
My code:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"OpenB"]){
OpenBViewController *controller = (OpenBViewController *)segue.destinationViewController;
controller.address = self.selectedCellText;
[self performSegueWithIdentifier:#"OpenB" sender:self];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
self.selectedCellText = [[[tableView cellForRowAtIndexPath:indexPath] textLabel] text];
[self performSegueWithIdentifier:#"OpenB" sender:self];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
First of all, you shouldn't call [self performSegueWithIdentifier:#"OpenB" sender:self]; inside of -prepareForSegue: method because -prepareForSegue is called when segue is about to be performed.
Second, check that you have your segue setup correctly. Make sure you have provided the same identifier to the segue in the storyboard that you are using with -performSegueWithIdentifier:
Your code should be as follows:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"OpenB"]){
OpenBViewController *controller = (OpenBViewController *)segue.destinationViewController;
controller.address = self.selectedCellText;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
self.selectedCellText = [[[tableView cellForRowAtIndexPath:indexPath] textLabel] text];
[self performSegueWithIdentifier:#"OpenB" sender:self];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
And keep in mind to setup a segue with identifier OpenB in storyboard.
I know this is old, but just leaving this here in case it happens to someone else.
Also, all code is in Swift 3, because my knowledge of Objective C syntax is next to nil.
The problem was most likely that the didSelectRow() method gets called after the segue was pushed. So when the prepare(ForSegue) one gets called, the selectedTextCell variable has not been properly initialized.
If you're connecting from the cell to the next ViewController via a segue created in the Interface Builder, you don't need to use didSelectRow() and probably you shouldn't, because the segue is likely to be always pushed before didSelectRow().
In that case, all you need to do is retrieve the information from the cell in the prepare() method.
The signature is:
func prepare(for segue: UIStoryboardSegue, sender: Any?)
The sender is whichever object triggers the segue. In this case, the cell that was selected. So, in prepare(), you would write something like this:
let myCell = sender as! UITableViewCell
controller.address = myCell.textLabel.text
If you need to access the row, for example, it would be:
controller.idx = self.tableView.indexPath(for: sender as! UITableViewCell)?.row
Of course, UITableViewCell can be replaced by any custom Cell class you may have.
Related
I have a controller with a listview that contain a custom cell.
I have created a modal segue from the cell to the next controller and I gave a name to this segue but when I click on the cell, prepareForSegue isn't called.
I could use the didSelectRowAtIndexPath and performSegueWithIdentifier but I have to send data to the next controller from the cell I've clicked on.
Any idea why the prepareForSegue isn't called? Or how to send data to the controller with another method?
You can get the cell data in didSelectRowAtIndexPath by getting the cell from the index of customCell that you clicked, and after you can performSegueWithIdentifier.
So let's make this easier:
Under your didSelectRowAtIndexPath method, add this line to get the properties of your customCell
YourCustomCell *customCell = (YourCustomCell *)[self.tableView cellForRowAtIndexPath:indexPath];
So now if you have something stored under your customCell you can access it from customCell instance.
After you managed to store or manipulate your data from customCell you do the performSegueWithIndenfier:
[self performSegueWithIdentifier:#"yourSegueID" sender:self];
Hope this helps
When you connect a segue from a cell to another view controller, unless it's a static table view, you'll have to trigger performSegueWithIdentifier from the didSelectRowAtIndexPath
After you execute performSegueWithIdentifier, prepareForSegue would be called.
In prepareForSegue, you can set up your destination view controller, which you can access via segue.destinationViewController
Like so:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[super prepareForSegue:sender sender:sender];
if ([segue.identifier isEqualToString:#"YOUR_SEGUE_NAME_HERE"]) {
UIViewController *destinationViewController = segue.destinationViewController;
}
}
Or if you need to set things up in the didSelectRowAtIndexPath , you could do (iOS7+ only)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME_HERE" sender:self];
UIViewController *destinationViewController = [self.transitionCoordinator viewControllerForKey:UITransitionContextToViewControllerKey];
}
Update:
Turns out #rdelmar is correct, it does work with dynamic cells.
All you have to do then is
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[super prepareForSegue:sender sender:sender];
if ([segue.identifier isEqualToString:#"YOUR_SEGUE_NAME_HERE"]) {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForCell:sender];
}
}
And you have the index path of the cell that was tapped. Then you can use that to query your datasource and find the object that was used to populate that cell.
Hi guys i am a beginner on Obj c Programming, I have created a "self segue"(segue to same view controller) from a tableviewcell. Now my problem is, i am setting few parameters in the prepareForSegue method, but somehow the segue already happens before this method is called(i am not even calling "performSeguewithIdentifier"). I understand that this might be because the segue is associated with the cell. But i found no other way to create a "self-segue"
please help.Btw i am using xcode6..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_selctdObj = [avObjArray objectAtIndex:indexPath.row];
if([_selctdObj isContainer])
{
[self performSegueWithIdentifier:#"isContainerSegue" sender:self];
}
else
{
[self performSegueWithIdentifier:#"isItemSegue" sender:self];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"isContainerSegue"]) {
// Get destination view
serverBrowseVC *sbvc = [segue destinationViewController];
[sbvc setServerSelected:_serverSelected];
[sbvc setBrowseObjID:_selctdObj];
}
}
Now invariably "isContainerSegue" gets executed ,even is the object is not a container. i also tried commenting the
//[self performSegueWithIdentifier:#"isContainerSegue" sender:self];
But every time "isContainerSegue" gets executed..
You said you weren't calling performSegueWithIdentifier, but you are. You shouldn't be if you've connected the segue from the cell. You also shouldn't implement didSelectRowAtIndexPath at all, just prepareForSegue. You can get the indexPath from the sender argument (the sender will be the cell) of prepareForSegue:sender:. If you're having a problem with the "if [_selctdObj isContainer]" clause, you need to post what isContainer does.
I am trying to push data from a UITableViewCell into another view controller. I have tried two separate ways, instantiateViewControllerWithIdentifier and also PrepareForSegue. In both instances the ViewController loads correctly but the data is not being passed across (either null, or the first array value).
Here is my instantiateViewControllerWithIdentifier method, when I log the variable within my ViewController it just returns null.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *testNumber = [jobNumberArray objectAtIndex:indexPath.row];
NSLog(#"Job is... %#",testNumber);
StandardInfoViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"StandardInfoViewController"];
controller.JobNr = [jobNumberArray objectAtIndex:indexPath.row];
[self.navigationController pushViewController:controller animated:YES];
}
Prepare For Segue
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"Details" sender: self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"Details"]){
StandardInfoViewController *controller = (StandardInfoViewController *)segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
controller.jobNumber = [jobNumberArray objectAtIndex:indexPath.row];
}
}
When I use the prepareForSegue call I get the first row of my Array, which I understand because it doesn't know the cell, but I don't know how to identify the Cell within the prepareForSegue call.
I hope this makes sense, and any help or pointers would be greatly appreciated.
Thanks
If you drag the segue FROM the tableView-cell in the storyboard, you will then get the cell itself as parameter sender.
then you can use tableView indexPathForCell:sender to get the actual index of the selected cell. Then just fetch your object normally.
I.e. you will not need to implement didSelectRowAtIndexPath
If you still want to use didSelectRowAtIndexPath, just pass the cell as the sender parameter manually. I.e:
[self performSegueWithIdentifier:#"Details"
sender:[self.tableView cellForRowAtIndexPath:indexPath]]
Although your first version with instansiateViewController should work, judging by your code.
Another pattern is to subclass the cells themselves, and let them have a property that is the object that they want to display. Then you can just fetch the object directly from the cell without calling the data-array itself.
Is this what you want?
This is how you identify Cell in prepareForSegue method.
**UITableViewCell *cell=[myTable cellForRowAtIndexPath:path];**
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"Details"]){
StandardInfoViewController *controller = (StandardInfoViewController *)segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
**UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];**
controller.jobNumber = [jobNumberArray objectAtIndex:indexPath.row];
}
}
I have a table view with cells created with:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"GalleryCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
NSMutableArray *gallery = [gallerys objectAtIndex:indexPath.row];
cell.textLabel.text = [gallery objectAtIndex:1];
return cell;
}
What I need to be able to do is within the didSelectRowAtIndexPath, fire a segue to launch another view, this will also send some information across using the prepareForSegue method.
This issue is I am not sure how to go about creating the segue to be used in this instance as within the storyboard I have nothing to attach it to (no buttons etc) and the cells are created within the code, is it possible to also create the segue in the code? Or is there another method to this?
Okay, you can attach it to your table view controller, it is not necessary to attach it to a button. Just go to the storyboard and do the following:
Right click on the VC that you would like to push.
Under Presenting Segues in the menu click and hold 'push' and drag it to your table view controller.
Choose manual when the dialog shows above your table view controller.
Select the segue after it appears and go to its attribute inspector.
Choose a name for the segue.
Call performSegue
simply drag a segue from your table to destination Controller and give a name for that.
And in didSelectRowAtIndexPath call
[self performSegueWithIdentifier:#"MySegue" sender:self];
then following method will get called
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// here you can pass any value to new ViewController;
if ([segue.identifier isEqualToString:#"MySegue"]) {
YourNewViewController *VC = segue.destinationViewController;
VC.data = yourData;
}
}
Push your view controller
[self performSegueWithIdentifier:#"yourSegueID" sender:self];
You can send the information as below
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"yourSegueID"]) {
YourViewController *yourVC = segue.destinationViewController;
yourVC.information = myInformation;
}
}
Hi I have a storyboard and am able to show a detail view when clicking on a table cell. I want to add extra functionality so that depending on what cell I click I show a different view controller. I tried dragging two segues from the same cell but it doesn't allow it.
My thinking was that I would have two segue's from the cell each pointing to a different view and then invoke the desired segue:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = indexPath.row;
NSLog(#"Selected Item :-) %#",[NSString stringWithFormat:#"%#",[myData objectAtIndex:row]]);
if(row %2 ==0){
NSLog(#"Even");
[self performSegueWithIdentifier:#"ShowSecondIndex" sender:self];
}else{
[self performSegueWithIdentifier:#"ShowSelectedMovie" sender:self];
NSLog(#"Odd");
}
}
I would then handle the segue in prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Prepare For Segue ID:%#",[segue identifier]);
if([[segue identifier] isEqualToString:#"ShowSelectedMovie"]){
Tab2_ItemViewController *vc = [segue destinationViewController];
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
NSLog(#"Selected Index: %d",selectedIndex);
[vc setSelectedItem: [NSString stringWithFormat:#"%#",[myData objectAtIndex:selectedIndex]]];
NSLog(#"String Value: %#",[NSString stringWithFormat:#"%#",[myData objectAtIndex:selectedIndex]]);
[vc setSelectedIndex:selectedIndex];
}else if([[segue identifier] isEqualToString:#"ShowSecondIndex"]){
NSLog(#"Viewing Second Index");
}
}
However it never shows the second view. Is this because its not possible to have two segues from a single table cell. I also tried dragging both segue's from the controller to each destination rather than one from the cell and one from the controller but sill no luck???
Don't try to hook up the Segues to a tableviewcell in this case. Hook them up to the View Controller itself.
Don't try to create multiple segues from a TableCell to other view controllers, you want to ctrl+drag from the view controller icon below the view controller in the storyboard interface to the viewcontrollers you want to segue to. Then it will allow you to set up multiple segues.
and then to actually make the segues work, you need to add identifiers to the segues themselves, which you can do by clicking on them and then giving it a name in the property inspector:
then, for the example of TableCells, in your UITableViewDelegate, in
-tableView:didSelectRowAtIndexPath:
you can use
- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender
to manually start a segue depending on your own logic of what segue should be chosen.
Here's a sample code from my demo project:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *segueName = nil;
if (type == kCore) {
segueName = #"segue1";
} else if (type == kStdlib) {
segueName = #"segue2";
}
[self performSegueWithIdentifier: segueName sender: self];
}
type is a property of view controller, which determines which segue should be performed.
As the above answer said, the key is to create segue by linking two view controllers.
In swift 3.1, with a segment control of two states
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var segue: String!
if selectedSegment == 0 {
segue = "segue1"
} else {
segue = "segue2"
}
self.performSegue(withIdentifier: segue, sender: self)
}