performSegueWithIdentifier doesn't show new view - ios

I'm having an issue with my performSegueWithIdentifier, because he fires and when I get a breakpoint on the viewDidLoad of the NextViewController he enters and executes fine. Problem is there is no output and the screen continues to show the CurrentViewController. What can be the error ?
(CurrentViewController is a TableViewController)
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_selected = [self.evlist objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"eventlist" sender:self];
return indexPath;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * event_id = [_selected objectForKey:#"id"];
NSString * event_name = [_selected objectForKey:#"label"];
[segue.destinationViewController setEvent_id:event_id];
[segue.destinationViewController setEvent_id:event_id];
[segue.destinationViewController setEvent_name:event_name];
}
(NextViewController is a ViewController)
- (void)viewDidLoad
{
[super viewDidLoad];
_evname_label.text = _event_name;
_evid_label.text = _event_id;
NSLog(#"This is strange %#",_event_name);
}
He logs everything as expected... the view doesn't show!

Your code appears correct. Are you sure the segue is configured correctly? Check the Style, Presentation and Transition styles.

Sorry but I had a bug in my coding... I was calling the prepareforsegue inside a for cycle and the problem was somewhere around it.
Prepareforsegue outside for and it was cool :) Thanks all

Related

Condition doesn't work

I use button in ViewController to go TableViewController. In TableViewController I create int NInt1. But when I go to TableViewController condition doesn't work.
ViewController.m
- (IBAction)Button:(id)sender {
MasterViewController *trns =[[MasterViewController alloc]init];
[_Button.titleLabel.text isEqualToString:#"1"];
trns.NInt1=1;
}
TableViewController.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(_NInt1 == 1){
return 5;
}else{
return 20;
}
}
If you are using the story pass the value like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.NInt1 = 1;
}
Now see the value of NInt in viewDidLoad of your destination view controller.
I think you need to modify like
- (IBAction)Button:(UIButton *)sender {
MasterViewController *trns =[[MasterViewController alloc]init];
if [sender.titleLabel.text isEqualToString:#"1"]{
trns.NInt1=1;
}
}
on that tableviewController viewDidload check like use NSLog for the object is 1 or not
If you use storyboard, then the destination view controller is not created from your IBAction. It can be verified easily : you never push or present the newly created view controller, which is local in your method.
Instead use prepareForSeguemethod as described in Jaimish answer.
I tried the solution.Finally I got.Thank you.The condition has worked now.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"goTableViewController"])
{
TableViewController *tableVC = (TableViewController *) segue.destinationViewController;
tableVC.NInt1 = 5;
}
}

Is using tableView:willSelectedRowAtIndexPath: correct way to pass variable?

Hello i am trying to pass variable with segue.
I am getting variable to pass with tableView:willSelectedRowAtIndexPath: is this correct way? If it is not, how should i achieve this? (Note: It is working like this.)
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedCoffeeShop = [coffeeShops objectAtIndex:indexPath.row];
return indexPath;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"coffeeShopDetailSegue"]) {
CoffeeShopDetailViewController *controller = (CoffeeShopDetailViewController *)segue.destinationViewController;
[segue destinationViewController];
controller.coffeeShop = selectedCoffeeShop;
}
}
If your segue is made from the cell itself, then there is no need to implement either willSelectRowAtIndexPath or didSelectRowAtIndexPath. You only need prepareForSegue:sender: since the sender argument will be the cell, and you can use that to get the indexPath you need,
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender {
if ([segue.identifier isEqualToString:#"coffeeShopDetailSegue"]) {
NSInteger row = [self.tableView indexPathForCell:sender].row;
CoffeeShopDetailViewController *controller = segue.destinationViewController;
controller.coffeeShop = coffeeShops[row];
}
}
That way to do it is absolutely fine.
Another way would be to remove the automatic segue trigger from storyboards and instead implement:
tableView:didSelectRowAtIndexPath: to call performSegueWithIdentifier:sender:.
It could look like this:
- (NSIndexPath *)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedCoffeeShop = [coffeeShops objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"coffeeShopDetailSegue" sender:self];
return indexPath;
}
In that case you still need your implementation of prepareForSegue:sender:.
You could also do it completely without segues, using UINavigationController, but then you'd have to instantiate the CoffeeShopDetailViewController programmatically as well.
Your approach is perfectly fine though!
As noted in the comments, you can remove [segue destinationViewController];, since this returns the destination view controller which you already saved in the variable controller in the line right above. :)

Object assigned to property of target view controller in prepareForSegue comes out as a UITableViewCell

I am trying to set the property of a View Controller I'm segueing to to a custom object (Restroom), but it's coming out as a UITableViewCell.
Here is code from the origin View Controller that is triggering the segue. The userDidSelectRestroomNotification method is called when a user selects a cell in a table view that lists restrooms - the application is then supposed to segue to a View Controller that lists the details of that restroom:
- (void)userDidSelectRestroomNotification:(NSNotification *)notification
{
Restroom *selectedRestroom = (Restroom *)[notification object];
[self performSegueWithIdentifier:#"ShowRestroomDetails" sender:selectedRestroom];
};
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowRestroomDetails"])
{
RestroomDetailsViewController *restroomDetailsViewController =
(RestroomDetailsViewController*)segue.destinationViewController;
restroomDetailsViewController.restroom = sender;
}
}
Here is the code in my data source where the notification is posed:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// post a notification when a selection is made
NSNotification *notification = [NSNotification
notificationWithName:RRTableViewDidSelectRestroomNotification
object:[self restroomForIndexPath:indexPath]];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
- (Restroom *)restroomForIndexPath:(NSIndexPath *)indexPath
{
return [self.restroomsList objectAtIndex:[indexPath row]];
}
Point being, I am sending along a Restroom object in my notification.
The issues comes when in the RestroomDetailsViewController, I am trying to set the text of a label to the name of the Restroom object I'm passing along:
#interface RestroomDetailsViewController ()
#property (weak, nonatomic) IBOutlet UILabel *nameLabel;
#end
#implementation RestroomDetailsViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.nameLabel.text = self.restroom.name;
}
#end
It crashes at self.nameLabel.text = self.restroom.name. When I inspect the objects, I see that my self.restroom object is actually a UITableViewCell. What confuses me further is that that UITableViewCell appears to be the cell that was selected by the user to trigger the segue -- i.e. the one set up in the data source:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSParameterAssert([indexPath section] == 0);
NSParameterAssert([indexPath row] < [_restroomsList count]);
UITableViewCell *restroomCell = [tableView
dequeueReusableCellWithIdentifier:restroomCellReuseIdentifier];
if(!restroomCell)
{
restroomCell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:restroomCellReuseIdentifier];
}
restroomCell.textLabel.text = [[_restroomsList objectAtIndex:[indexPath row]] name];
return restroomCell;
}
I'm not understanding why this happens and how to get that restroom property properly assigned to the Restroom object.
Why are you using postnotification ?
I don't see any requirement here to use notification. A simple function with parameter will do the work.
Try Following way to call segue
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"ShowRestroomDetails" sender:[self restroomForIndexPath:indexPath]];
}
- (Restroom *)restroomForIndexPath:(NSIndexPath *)indexPath
{
return [self.restroomsList objectAtIndex:[indexPath row]];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
Restroom *selectedRestroom = (Restroom *)sender;
if ([segue.identifier isEqualToString:#"ShowRestroomDetails"])
{
RestroomDetailsViewController *restroomDetailsViewController =
(RestroomDetailsViewController*)segue.destinationViewController;
restroomDetailsViewController.restroom = selectedRestroom ;
}
}
I understand it's not typical to have notifications being posted when cells are pressed - but that's how I'm choosing to implement this application currently.
That being said, here's how I ended up getting this to work (thanks to a comment by #rdelmar saying to check what order the methods are being called in):
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowRestroomDetails"])
{
if([sender isKindOfClass:[Restroom class]])
{
RestroomDetailsViewController *restroomDetailsViewController = (RestroomDetailsViewController*)segue.destinationViewController;
restroomDetailsViewController.restroom = sender;
}
}
}
I found that the prepareForSegue method was being triggered when a cell was pressed before my userDidSelectRestroomNotification method. However, I want userDidSelectRestroomNotification to actually be the method that triggers prepareForSegue because it creates the needed Restroom object. Thus I put a check in my prepareForSegue that makes sure the incoming object is a Restroom instance.
All that being said - I don't know if this is more of a hack than a solution.

prepareForSegue getting called twice, with Attempt to present <UINavigationController> while presentation is in progress

I am new to ios programming and asking here, but I visit all the time! I am stumped at why I am getting this problem, it compiles with no errors and I have checked and checked all my outlets and identifiers in my MainStoryboard.
I have 2 UITableViewControllers, I am passing a string from the first to the second when the user selects an item in the table, so in
FirstTableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int sel = indexPath.row;
if (sel == 0) {
_keyName = [NSString stringWithString:_string1];
NSLog(#"the table was selected at cell 0, %#", _string1);
}
if (sel == 1) {
_keyName = [NSString stringWithString:_string2];
}
// more code below...
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ResultsSegue"])
{
UINavigationController *navigationController = segue.destinationViewController;
ResultsViewController *rv = [[navigationController viewControllers] objectAtIndex:0];
[rv setResults: _keyName];
NSLog(#"in the progress view, %#", _keyName);
//rv.delegate = (id)self;
rv.delegate = self;
}
}
And in my ResultsViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"in the results, %#", _results);
NSLog(#"in the results view");
}
In the NSlog readout I get:
...
in the progress view, (null)
in the results, (null)
in the progress view, The Right String
Warning: Attempt to present on
Then when I hit the cancel button to return to the firstTableview and press the detail view again it no longer shows null..
in the progress view, The Right String
in the results, The Right String
in the progress view, The Right String
The problem is prepareForSegue is called before didSelectRowAtIndexPath. You should just eliminate the didSelectRowAtIndexPath method, and do everything in prepareForSegue. You can use the following line to get the indexPath you need:
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Rob's answer helped me, as well - thanks! I'm coding in Swift, so for those who run into this while Swifting, here's how to get the index (or index row) clicked on in Swift 3:
var rowClicked = (self.tableView.indexPathForSelectedRow?.row)!
May be your segue is connection start form the table view cell instead of view controller.
I had same issue I removed the segue from the table view cell and added back at view controller level.

UITableView only sending data to Detail View Controller on Second Try

Hey there I have been working on a transit app for some time and have been stuck with this issue for a while now.
I am using iOS 5 and a storyboard. Basically I have a UITableView that displays favorite bus stop locations, when a user selects a row I use:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Favorite *favorite = [self.favoriteItems objectAtIndex:indexPath.row];
stopString = favorite.title;
routeString = favorite.subtitle;
}
With the stop and route information of the cell the user chose I then prepare for a segue that corresponds to a segue on my storyboard, pushing a detail view controller that uses the stop name and route name to display times from a plist.
I am fairly new to Objective C and iOS so I am using a segue that my friend told me would work, however, it might be the problem. The segue looks like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destination = segue.destinationViewController;
if ([destination respondsToSelector:#selector(setDelegate:)])
{
[destination setValue:self forKey:#"delegate"];
}
if ([destination respondsToSelector:#selector(setSelection:)])
{
NSString *route = routeString;
NSDictionary *selection1 = [NSDictionary dictionaryWithObjectsAndKeys:route, #"route", stopString, #"stop", nil];
[destination setValue:selection1 forKey:#"selection"];
}
}
After the segue in my DetailViewController I grab the stop and route information in the view DidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
route = [selection objectForKey:#"route"];
stopName = [selection objectForKey:#"stop"];
NSLog(#"stopName: %#", stopName);
NSLog(#"routeName: %#", route);
}
Here is where my problems arise. When I run the simulator and click on an a cell in my table view, I am pushed to the DVC, however, the stopName and routeName are both null, so no information was sent or received. BUT, if I go back to the table and click another cell, the routeName and stopName are filled with the information that should have sent the first time I clicked a cell. If I continue this process it continues to send the information for the cell tapped previously, not currently.
So basically information is sending but only after I go through the segue twice. Obviously I want it to send the information and receive it the first time, but it is delayed and driving me nuts. I appreciate any help someone can give me as I have been searching the internet for days now trying to fix this issue, thank you so much in advance for any assistance!
prepareForSegue: is being called before didSelectRowAtIndexPath:. This is why the values you see always are lagging behind.
The better solution is to get the stopString and routeString values in your prepareForSegue: method (and not use didSelectRowForIndexPath: at all). The key to doing this is to realize that the sender parameter value being passed to prepareForSegue: is the UITableViewCell that was tapped. You can use the UITableView method indexPathForCell to get the cell's indexPath in your table, and then use that to look up the data in your favoriteItems array.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UITableViewCell *cell = (UITableViewCell*)sender;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Favorite *favorite = [self.favoriteItems objectAtIndex:indexPath.row];
stopString = favorite.title;
routeString = favorite.subtitle;
UIViewController *destination = segue.destinationViewController;
if ([destination respondsToSelector:#selector(setDelegate:)])
{
[destination setValue:self forKey:#"delegate"];
}
if ([destination respondsToSelector:#selector(setSelection:)])
{
NSString *route = routeString;
NSDictionary *selection1 = [NSDictionary dictionaryWithObjectsAndKeys:route, #"route", stopString, #"stop", nil];
[destination setValue:selection1 forKey:#"selection"];
}
}
Make sure that you are NOT connecting the segue to the next view controller to the tableView CELL directly. Connect to the whole UITableViewController / UIViewController (whichever you are using) and give a name, say "segueNameInStoryboard".
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Favorite *favorite = [self.favoriteItems objectAtIndex:indexPath.row];
stopString = favorite.title;
routeString = favorite.subtitle;
/* add this line */
[self performSegueWithIdentifier:#"segueNameInStoryboard" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"segueNameInStoryboard"])
{
UIViewController *nextViewController = segue.destinationViewController;
nextViewController.delegate = self;
NSDictionary *selection1 = [NSDictionary dictionaryWithObjectsAndKeys:routeString, #"route", stopString, #"stop", nil];
nextViewController.selection = selection1;
}
}

Resources