I'm following a tutorial from a book and everything went fine untill i had to recieve the data from the tableView, i must mention that i modified some of the basic tutorial to fit my needs as i work with JSON values comming from a API. It crashes when i reference the value using self and says that the variables is nil. must also mention that the label has been added as a reference outlet and the customClass also as been created and added referenced with the View. Aditional to this added properly Segue to the detailViewController
UserDetailViewController.h
#interface UserDetailViewController : UIViewController
#property (nonatomic, strong) NSString *labelName;
#property (nonatomic, strong) IBOutlet UILabel *detailLabelName;
#end
UserDetailViewController.m
This is the code that does the transition between Table and detailView but there are a few values that does not belong to the code i have such as recipeName and recipeNames as you can see below:
recipeName is on my code labelName
recipeNames is on my code a dictionary [dictionary objectForKey:#"name"]
and have no idea how to put this part together. :(
// Here is where I handles the Data Transfer
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"userDetailView"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipeName = [recipeNames objectAtIndex:indexPath.row];
}
}
According to my understanding, you want to set text for detailLbelName depending on labelName. And this value is coming from your parent view controller.
You must be doing something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UserDetailViewController *detailController = [[UserDetailViewController alloc]initWithNibName:#"UserDetailViewController" bundle:nil];
self.detailController.lableName = #"Your Text According to Cell"
[self.navigationController pushViewController:detailController animated:YES];
}
In your UserDetailViewController:
- (void)viewWillAppear
{
self.title = self.labelName;
[self.detailLabelName setText:self.labelName];
}
To receive the data from tableView need to handle tableView delegate did select method and passed all required data to detailLabelName then refresh the screen.
Move the assignment lines in viewDidLoad to viewWillAppear.
- (void)viewWillAppear
{
self.title = self.labelName;
_detailLabelName.text = _labelName; // this is the breakpoint
}
Then, hwever you are storing the string in the table view (i assume you mean the cells specifically) then you may assign the value extracted from the table view cell after creating the detail view controller but before it is pushed onto the navigation stack and crashes your app.
please try this
In
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
of your table view do this.
UserDetailViewController *detailsView = [[UserDetailViewController alloc] initWithNibName:"Your nib name" bundle:[NSBundle mainBundle]];
UITableViewCell *reqDcell = [tableView cellForRowAtIndexPath:indexPath];
detailsView.labelName = //Text from reqDcell goes here. In particular the recipe name
[self.navigationController pushViewController:tableViewControls animated:YES];
Hope this helps.
********** EDIT ************
Ok so inorder to pass values using a dictionary , you would need an array of dictionaries which hold your data.
In terms of the link you posted, i have modified it for your understanding to use dictionaries.
recipeNames = #[[NSDictionary dictionaryWithObject:#"Mushroom" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Hamburger" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Pasta" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Pizza" forKey:#"Recipie Name"],
[NSDictionary dictionaryWithObject:#"Noodles" forKey:#"Recipie Name"]];
The dictionary here will hold the json data that you have.
in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
// Display recipe in the table cell
NSDictionary *dict = [recipeNames objectAtIndex:indexPath.row];
cell.nameLabel.text = [dict valueForKey:#"Recipie Name"];
and the prepareForSegue function.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
NSDictionary *dict = [recipeNames objectAtIndex:indexPath.row];
destViewController.recipeName = [dict valueForKey:#"Recipie Name"];
}
}
I hope this is helpful
Related
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
Display details in second UITableViewController
My application is a simple Recipebook to understand UITableViewControllers. The application contains two UITableViewControllers. The first UITableViewController contains a UITableView with a list of the recipe names. If you select a cell you will segue to the second UITableViewController. The second UITableViewController contains a UITableView with a list of the ingredients.
The application contains the following classes:
RecipeTableViewController (first)
IngredientTableViewController (second)
RecipeObject
RecipeData
The RecipeObject Class contains two properties. One property of type NSString with the recipe name. The other property is of type NSArray with the ingredients. The RecipeObject objects are in the RecipeData class.
RecipeObject *recipe1 = [[RecipeObject alloc]init];
recipe1.name = #"Fresh Coconut Cake";
recipe1.ingredients = [NSArray arrayWithObjects:#"Coconut cups", #"Milk", #"Baking powder", #"Butter", #"Sugar", #"Eggs", nil];
The RecipeData is called in the RecipeTableViewController to display the recipe names in the tableView.
Message from RecipeData class to RecipeTableViewController:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.recipes = [RecipeData allRecipes];}
Display names in the tableView:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"recipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
RecipeObject *recipes = [self.recipes objectAtIndex:indexPath.row];
cell.textLabel.text = recipes.name;
return cell;
}
How to add the recipe1.ingredients array to the IngredientsTableViewController?
Any help is highly appreciated!
Perform a segue when a recipe is selected. In the prepare for segue-method take the selected recipe and pass the ingredients to the ingredientsTableViewController.
Something quite similar to this:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"to_Ingredients" sender:self];
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"to_Ingredients"]) {
IngredientTableViewController *ingredientsTableViewController = (IngredientTableViewController *)[segue destinationController];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeObject *recipe = [self.recipes objectAtIndex:indexPath.row];
ingredientsTableViewController.ingredients = recipe.ingredients;
}
}
If you don't use a storyboard where you set this segue you just need the first method which the should looks like this:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
IngredientTableViewController *ingredientsTableViewController = [[IngredientTableViewController alloc]init];
RecipeObject *recipe = [self.recipes objectAtIndex:indexPath.row];
ingredientsTableViewController.ingredients = recipe.ingredients;
[self showDetailViewController:ingredientsTableViewController sender:self]
}
I am trying to send an NSMutableArray of the chosen cell to another view when a cell is clicked. I have the array of the chosen cell, but I can't get it to pass over.
"SearchResultsModalTableViewController.m"
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *aVenue = [self.venues objectAtIndex:indexPath.row];
DetailSearchResultViewController *detailVC =[[DetailSearchResultViewController alloc]init];
detailVC.venueInfo = aVenue;
NSLog(#"%#",aVenue);
}
When you use storyboards, you usually add segues from table cells to a destination storyboard. If that is what you are doing, then the way to deal with the selection is in the prepareForSegue: method of your view controller.
Here is an example. I am assuming that DetailSearchResultViewController in your code is a UINavigationController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
DetailSearchResultViewController* destinationViewController = (DetailSearchResultViewController*)segue.destinationViewController;
NSIndexPath *p = self.tableView.indexPathForSelectedRow;
NSUInteger idx = p.row;
NSMutableArray *aVenue = [self.venues objectAtIndex:indexPath.row];DetailSearchResultViewController *detailVC =[[DetailSearchResultViewController alloc]init];
destinationViewController.venueInfo = aVenue;
[super prepareForSegue:segue sender:sender];
}
my code snippet //
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// [tableView deselectRowAtIndexPath:indexPath animated:YES];
if(indexPath.section == 0)
{
if(indexPath.row == 1)
{
WebServiceHandler *handler = [[WebServiceHandler alloc]init];
handler.requestType = eSuburb;
NSMutableURLRequest *searchDetailsRequest = [Service parseGetSuburb:nil];
NSLog(#"user details request of str== %#",searchDetailsRequest);
[handler placeWebserviceRequestWithString:searchDetailsRequest Target:self Selector:#selector(getListOfSuburb:)];
}
after response it jumps into another class with list of all it is data,among all those data I want to populate with it one which user selects
Not sure how you are doing this, but here is how if you are using segues. In this example, each of my table cells contained their relative information in an NSMutableDictionary. The receiving view controller had a NSMutableDictionary property to receive all of the sent data. The last two lines create a ViewController object and has its Dictionary property equal the Dictionary being sent from the selected cell in the table view.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSString *identifier = segue.identifier;
if ([identifier isEqualToString:#"SegueName"]) {
// first get data
NSIndexPath *selectedIndexPath = self.tableView.indexPathForSelectedRow;
NSMutableDictionary *cellData = self.aDictionary[selectedIndexPath.row];
ViewController *nextViewController = segue.destinationViewController;
nextViewController.aDictionary = cellData;
}
}
I would Suggest against using the callback method here. That is not the right way to carry this out.
According to my understanding, what you want to do is once the user selects a row, you wish to pass the selected row's data back to the viewcontroller(lets assume 'vcA') which called the one with the tableview('vcB')...
If this is so you should create a protocol and hence use a delegate to notify the viewcontroller 'vcA' about the selection event and hence pass the required data just as #inertiatic suggested.
I need more help with my first Table View app.
I have .plist with continents, countries and other info:
I work with a StoryBoard and I have 3 View Controllers (MasterVC - for continents, MiddleVC - for countries, DetailVC - for detailed info). I have already continents displayed in UITableView on my MysterVC. Now I want to pass information about what was pushed to the MiddleVC, for example that Europe was pushed and the to display European countries in a table view on my MiddleVC.
I guess that I should do it in didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
//is it correct way to catch the info about which continent was pressed?
NSString *ContinentName = [[world allKeys] objectAtIndex:indexPath.row];
//I don't know how to pass the info forward
}
Or maybe I should use segue for passing data?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showMiddle"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = _objects[indexPath.row];
//??is everything what needed here??
[[segue destinationViewController] setDetailItem:object];
}
}
And I am not sure how to deal with the passed info from MasterVC, here in MiddleVC. Although I prepared some initial coding:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
//I think countries arrays will be needed here
NSArray *namesOfAfricanCountries = [africa allKeys];
NSString *AfricanCountryName = [namesOfAfricanCountries objectAtIndex:indexPath.row];
NSArray *namesOfEuropeanCountries = [europe allKeys];
NSString *EuropeanCountryName = [namesOfEuropeanCountries objectAtIndex:indexPath.row];
//how to feel cells only with the proper continent's countries?
cell.textLabel.text = ???;
return cell;
}
Will appreciate any help.
Are you using a UINavigationController? If so:
Setup a 'push' segue from your Master VC to your Detail VC and have a property in your details VC to hold the 'continent' dictionary.
implement 'prepareForSegue', here you can use the indexPathForCell: on the sender argument to find out which cell was tapped.
Use the row in the index path to locate the country in your dictionary
In your prepare for segue, use segue.destinationViewController to get a handle on your detail VC and set it's continent property to the country dictionary from your data source. (you only want to pass forward the continent dictionary containing the countries in that continent, not your whole data source).
Then in the detail VC' cellForRowAtIndexPath:
then if you only want to display the country name in the cell assuming the names are keys...
NSString *key = [self.continentDict allKeys][indexPath.row];
cell.textLabel.text = key;
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;
}
}