passing value to destination controller - iphone

I am passing ID from UITABLEVIEWCONTROLLER to another UITABLEVIEWCONTROLLER but it throw the following error.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITabBarController setCityId:]: unrecognized selector sent to instance 0x75225e0'
here us the prepareForSegue function:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"cityPushToTab"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
featuredViewController *destViewController = segue.destinationViewController;
destViewController.cityId = [productKeys objectAtIndex:indexPath.row];
}
}
the function did well before i call the cityId of featured controller. I have tried to logg the productKeys which print the correct values but it is terminating when I try to assign value to destination view controller object. please help.

Are you sure destViewController is of class featuredViewController ? I'm sure it's not. The crash log tells it's a UITabBarController.
What I recommend is create a class that inherits from UITabBarController. I'll call it MyTabBarViewController. Set the class of your tab bar controller in your storyboard to this new class.
In MyTabBarViewController.h, create a property :
#property (nonatomic, strong) id cityId;
(note that cityId can be of any type you need, e.g. NSString, NSNumber, ...).
Then, change your prepareForSegue code :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"cityPushToTab"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
MyTabBarViewController *destViewController = segue.destinationViewController;
destViewController.cityId = [productKeys objectAtIndex:indexPath.row];
}
}
Next, in the .m files of the 4 view controllers that are in your tab bar, you can use this code to access cityId :
// Cast the viewcontroller's tab bar to your class
MyTabBarViewController *tabBarController = (MyTabBarViewController*)self.tabBarController;
// Access your property
id cityId = tabBarController.cityId;
// You can test to see if it works by casting to an NSString and NSLog it
NSString *cityIdString = (NSString*) tabBarController.cityId;
NSLog (#"%#", cityIdString);

Related

Not able to set a Label on a view by using model segue

problem StoryBoard
I want to use the model segue. By clicking on 'Year' button it should go to the 'Year View Controller' click on the table cell and screen is set to initial view controller set the Label 1 in the view controller.
Person.h
#import <Foundation/Foundation.h>
#interface CarObj : NSObject
#property (nonatomic, strong) NSMutableString *Year;
#property (nonatomic, strong) NSMutableString* Name;
#end
After that click on the Name button it should go to the Name View Controller and on click it should save the info of cell to the 'Name' parameter of Person.h.
How to implement this? I am not able to set the Label 1 and Label 2....
for segue I am using :
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"GrabYear"])
{
YearViewController *yvc = [segue destinationViewController];
[yvc setCurrentCar:currentCar];
}
}
and for the row selection I am using:
MenuViewController *mvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MenuSB"];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
CarObj *c = [cars objectAtIndex:[path row]];
[mvc setCurrentCar:c];
[mvc viewDidLoad]; // I am not getting previous view loaded automatically
[self dismissViewControllerAnimated:YES completion:^{}];
the string which I am getting in currentCar.year is not able to set the Label by using
[yearLabel setText:currentCar.year];
The controller's call to [controller view] has not happened in the api's chain of events.
Hence, any value you set on the view's sub controls without first loading child controls, will be overwritten, leaving you befuddled with the mystery.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
id vc = [segue destinationViewController];
MyController *controller = (MyController*)vc;
//You'll need lazy load controller child controls "now"! with this method call
[controller view];
//now you can set controls
controller.myLabel.text = #"Value will now persist";
//note objects not owned by the "view" can be set here without the hack
controller.myContextSting = #"This value will persist without the hack";
}
You problem is this code:
MenuViewController *mvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MenuSB"];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
CarObj *c = [cars objectAtIndex:[path row]];
[mvc setCurrentCar:c];
[mvc viewDidLoad]; // I am not getting previous view loaded automatically
[self dismissViewControllerAnimated:YES completion:^{}];
Because you are creating a new instance of your MenuViewController, configuring it and then throwing it away.
What you want to do is add a delegate property to the year and name view controllers and have your MenuViewController set itself as the delegate in prepareForSegue:. Then, on row selection you would do something like:
[self.delegate setCurrentCar:c];
Instead of what you're currently doing with mvc.

UITableView prepareForSegue assigning indexPath to sender?

In the code below I am just trying out setting up a segue directly from the UIViewController to a DetailViewController. I usually do the segue from the UITableViewCell (which I think is clearer) but this time I just wanted to try going directly from the ViewController using -tableView:didSelectRowAtIndexPath:
My question is: I got to a situation where I needed to access the UITableViewCell indexPath from within -prepareForSegue:sender: my solution was to send the indexPath via sender. Usually I would set sender to self here, I have looked around and I can't find any reference to this, I am just curious if using sender to pass an indexPath is acceptable? I am pretty sure it is, and I am sure I have read that you can somewhere before, but I can't find any reference to it now.
// ------------------------------------------------------------------- **
// DELEGATE: UITableView
// ------------------------------------------------------------------- **
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"%s", __PRETTY_FUNCTION__);
[self performSegueWithIdentifier:#"SEGUE_TWO" sender:indexPath];
}
// ------------------------------------------------------------------- **
// SEGUE: ViewController_ONE > DetailViewController
// ------------------------------------------------------------------- **
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"%s", __PRETTY_FUNCTION__);
if([[segue identifier] isEqualToString:#"SEGUE_TWO"]) {
NSUInteger cellRow = [(NSIndexPath *)sender row];
DetailViewController *destinationController = [segue destinationViewController];
[destinationController setDataString:[[self dataList] objectAtIndex:cellRow]];
}
}
EDIT: What I was looking for in this case was
NSIndexPath *indexPath = [[self tableView] indexPathForSelectedRow];
essentially a way to get indexPath into -performForSegue:sender: without having to pass it via the sender parameter (in -performSegueWithIdentifier:sender:)
I typically avoid using the sender in prepareForSegue: because it could be anything. This makes asserting that your sender is what you are expecting more cumbersome and fragile. Also, I prefer to check for the class of the destinationViewController object rather than the segue name. Your functionality is tied to your object (or more specficially its interface), not the title of your segue, so checking your class makes it clear what you are trying to accomplish.
Below is the usual template I use in production when segueing from a UITableView. Note that you should always check if the destinationViewController is embedded in a nav controller and then check the class of the object as well to make sure you are handling it correctly. Finally, use an assert to ensure that somewhere down the line you haven't added some new segue that you forgot to handle.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// unwrap the controller if it's embedded in the nav controller.
UIViewController *controller;
UIViewController *destVC = segue.destinationViewController;
if ([destVC isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = (UINavigationController *)destVC;
controller = [navController.viewControllers firstObject];
}
else
{
controller = destVC;
}
if ([controller isKindOfClass:[DetailViewController class]])
{
DetailViewController *vc = (DetailViewController *)controller;
NSIndexPath *ip = [self.tableView indexPathForSelectedRow];
[vc setDataString:[[self dataList] objectAtIndex:ip.row]];
}
else
{
NSAssert(NO, #"Unknown segue. All segues must be handled.");
}
}
You could use UITableView's method indexPathForCell. I hope you have a tableView instance variable.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([sender isKindOfClass:[UITableViewCell class]]) {
NSIndexPath * indexPath = [self.tableView indexPathForCell:sender];
//Your code here
}
}

UITableViewController unrecognized selector sent to instance

I have a tableviewcontroller and a detailtableviewcontroller when I pass an integer I get
-[UITableViewController setSurveyNumber:]: unrecognized selector sent to instance
Bizard thing is exact same code works for tableviewcontroller to -> uiviewcontroller
table -> table code
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"pushSurveyDetails"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSInteger row = [indexPath row];
SurveyDetailViewController *surveyController = [segue destinationViewController];
surveyController.surveyNumber=row;
}
}
in SurveyDetailViewController.h
#interface SurveyDetailViewController : UITableViewController
{
}
#property int surveyNumber;
#end
SurveyDetailViewController.m
#implementation SurveyDetailViewController
#synthesize surveyNumber;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Survey Number is %i",surveyNumber);
}
why this error occurs?
The error message indicates that [segue destinationViewController] returns a UITableViewController and not a SurveyDetailViewController as expected.
The controller class can be set in the storyboard file.

next view controller is not loaded when the segue is performed

I am still new to the storyboard stuff. I spent two days debugging this problem. It seems the destination view controller of a segue is not working properly when the -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender is called.
I have a table view and when a cell is tapped, it calls for a segue
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
VAItem *item = [category itemAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"SegueShowDetail" sender:item];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"SegueShowDetail"]) {
VADetailViewController *detailViewController = segue.destinationViewController;
detailViewController.item = (VAItem*) sender; // <-- THIS ASSIGNMENT DOES NOT WORK
}
}
My debugging shows, the item is correctly passed down to prepareForSegue but the detailViewController.item is a wild pointer. It's not initialized and the = assignment does not have any effect.
I put a breakpoint in VADetailViewController's viewDidLoad and found out that the item variable is still the wild pointer address even though the assignment has taken place.
#interface VADetailViewController : UIViewController
// data
#property (nonatomic, retain) VAItem *item;
#end
item is also correctly synthesized.
Any help is much appreciated
Leo
If you're using a storyboard segue to transition to the next viewcontroller you don't need to use tableVeiew:didSelectRowAtIndexPath: in this situation. Depending how you have things set up that could be contributing to the problem.
In your storyboard, make sure you have drawn your push segue from your tableview's Prototype Cell to the detail view controller (i.e. from the cell, NOT from the tableViewController). If you have your storyboard set up that way your segue will be triggered as soon as the user selects a cell. A reference to the cell itself will be passed to prepareForSegue:sender: as the sender parameter. You can then inspect that object to find out which row was clicked in that method.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"SegueShowDetail"]) {
// sender will be the tableview cell that was selected
UITableViewCell *cell = (UITableViewCell*)sender;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
VAItem *item = [category itemAtIndex:indexPath.row];
VADetailViewController *detailViewController = segue.destinationViewController;
detailViewController.item = item;
}
}
You really only want to use one of
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
to pass your data along to the next view controller. If you want to use the latter in your case, then you need to change your code to something along the lines of:
if ([segue.identifier isEqualToString:#"SegueShowDetail"]) {
VADetailViewController *detailViewController = segue.destinationViewController;
detailViewController.item = [catagory itemAtIndex:[self.tableView indexPathForSelectedRow].row];
}
I think you were getting an error because of what you assigned your sender. Here is the reference to the docs that explain what 'sender' should be.
https://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instm/UIViewController/performSegueWithIdentifier:sender:
Hope this helps.

Data is not passed to view

I want to pass an "human" that was selected in a tableView to a detailViewController. I connected them in Interface Builder via Storyboards and set up an own segue identifier. The NSLog is called but it returns (null). Also, the in the detailView, nothing is shown but the default content…
My tableViewController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"didSelectRow"]) {
DetailViewController *detailViewController = (DetailViewController *)[segue destinationViewController];
Human *employee = [[Human alloc] init];
employee = [people objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
[detailViewController setHuman:employee];
}
}
And the detailViewController
-(void)setHuman:(Human *)human
{
NSLog(#"%#",employee.name);
employee = human;
nameLab.text = employee.name;
descriptionLab.text = employee.description;
imageViewBig.image = [employee imageForName];
}
Thanks in advance!
Your variable human in setHuman contains employee. Thus you should assign the variable human to the #property human of the DetailViewController in your function. Or better still, just assign the property from outside: detailViewController.human = employee.
Your NSLog returns null because you call it before assigning human to employee.
Maybe choosing less repetitive ivar names would help.