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.
Related
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.
So I have a standard method that everyone uses in the prepare for segue.
When I think logically "prepare" means do this before the segue is called.
But I have set up 3 table cells that all have 1 segue to the SecondViewController.
When I test that it works perfectly no errors.
Now when I want to add to this app that when the user selects the first cell the label "labeltje" get another text value this does not happen.
Of course this code is in my TableViewController.m file and not in the DagenViewController, which is my second controller.
What am I not seeing?
Dagenviewcontroller is imported etc. no issues there.
This is the prepareforsegue bit of code:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DagenViewController *secondVC = (DagenViewController *)segue.destinationViewController;
if([segue.identifier isEqualToString:#"vrijdagSegue"])
{
NSString *vrijdag = #"vrijdag";
secondVC.labeltje.text = vrijdag;
}
else if([segue.identifier isEqualToString:#"zaterdagSegue"])
{
NSString *zaterdag = #"zaterdag";
secondVC.labeltje.text = zaterdag;
}
else {
NSString *zondag = #"zondag";
secondVC.labeltje.text = zondag;
}
}
Or is there a way to put something in the ViewDidLoad method of my SecondViewController that checks which segue was used?
Thank you for reading.
Try to do this way:
DagenViewController.h file
#property (strong, strong) NSString *preText
DagenViewController.m file
- (void) viewDidLoad
{
self.labeltje.text = preText;
}
In Your Method
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DagenViewController *secondVC = (DagenViewController *)segue.destinationViewController;
if([segue.identifier isEqualToString:#"vrijdagSegue"])
{
secondVC.preText = #"vrijdag";
}
else if([segue.identifier isEqualToString:#"zaterdagSegue"])
{
secondVC.preText = #"zaterdag";
}
else {
secondVC.preText = #"zondag";
}
}
When prepareForSegue:sender: is called you are accessing a label that is nil since the view controller's view was not yet loaded. Create a string property(that you will set in prepareForSegue:sender:) and then in your DagenViewController viewDidLoad method set the label's text from that string property.
I know this should be a simple thing to fix, but I can't see what's going wrong. May be extra pair will help. Here is what I am trying to do.
In my table view controller, there is an (+) button on the navigation controller to add new item.
I have a modal segue that takes it to the next view controller. User fills in a form and hit saves the table view controller reloads with the newly added record.
To do this, I implemented protocol with a delegate.
MyFormViewController.h
protocol MyCustomDelegate <NSObject>
#required
- (void)addNewRecord:(myFormViewController *)formViewController itemToAdd:(Item *)item;
#end
#property (nonatomic,weak) id<MyCustomDelegate> delegate;
MyFormViewController.m
#synthesize delegate;
- (IBAction)addItem:(id)sender {
Item *item = [[Item alloc]init];
item.name = itemName.text;
item.desc = itemDescription.text;
// I am having problem here, self.delegate is being null even though, it's being set in prepareForSegue.
if ([self.delegate respondsToSelector:#selector(addNewRecord:)]) {
[self.delegate addNewRecord:self itemToAdd:item];
}
else{
// delegate is getting set to null for some reason.
NSLog(#"Delegate method not getting called...%#",delegate);
}
}
in MyTableViewController.h
#interface MyTableViewController : UITableViewController
MyTableViewController.m
-(void)addItem:(myFormViewController *)formViewController itemToAdd:(Item *)item{
if(item)
{
MyClass *_itemClass = [[MyClass alloc]initWithPath:#"items/"];
[_itemClass addItemForUser:item];
}
[formViewController dismissViewControllerAnimated:YES completion:nil];
}
in my prepareForSegue method I am setting my tableviewcontroller as delegate.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"addItemSegue"]){
myFormViewController *_showaddTopic = [[myFormViewController alloc]init];
_showaddTopic.delegate = self;
}
After all this, my delegate in myFormViewController is being set to "null". I am not sure why it's not working. It's pretty basic stuff but giving me hard time.
Thank you
myFormViewController *_showaddTopic = [[myFormViewController alloc]init];
_showaddTopic.delegate = self;
There's your problem. You are creating a new MyFormViewController. But that's the wrong MyFormViewController; you want to use the one that is already the segue's destination controller. So you are setting the wrong object's delegate.
(PS Notice my use of a capital letter to start the name of a class? Always do that.)
maybe _showaddTopic.delegate = self; can not written here and shuold this object alloc after at once
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);
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.