Search code examples
iosobjective-cuitableviewnsarraycell

How to make NSArray an acceptable value for cell.textLabel.text?


Simple Recipebook application

In my recipeBook application I have 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.

In my application I use a RecipeObject class what contains two properties (name (type: NSString) and ingredients (type: NSArray). The recipeObject objects are all declared in the RecipeData class, like this:

RecipeObject *recipe1 = [[RecipeObject alloc]init];
recipe1.name = @"Fresh Coconut Cake";
recipe1.ingredients = [NSArray arrayWithObjects:@"Coconut cups", @"Milk", @"Baking powder", @"Butter", @"Sugar", @"Eggs", nil];

In the First UITableViewController I managed to print out the recipe names for each cell. See the following code:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString *cellIdentifier = @"recipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

TostiObject *recipes = [self.recipes objectAtIndex:indexPath.row];
cell.textLabel.text = recipes.name;

return cell;

I declared an NSArray property in the First UITableViewController called self.recipes to connect the RecipeData. I also did the following in the second UITableViewController.

self.recipes = [RecipeData allRecipes];

The problem occurs in the second UITableViewController:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = @"ingredientCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

RecipeObject *recipe = [self.recipes objectAtIndex:indexPath.row];

cell.textLabel.text = [recipe.ingredients objectAtIndex:indexPath.row];

return cell;

Because cell.textLabel.text only accepts an NSString value and recipe.ingredients is an NSArray. I want to connect the ingredients data (an NSArray) to the cell.textLabel.text in the second UITableViewController.

Maybe someone can help me solve this problem. All help is highly appreciated!

- Other information -

The prepareForSegue method (first UITableViewController):

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"ingredients"]) {
        SecondTableViewController *IngredientsTVC = (SecondTableViewController *)segue.destinationViewController;
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        RecipeObject *recipe = [self.recipes objectAtIndex:indexPath.row];
        IngredientsTVC.recipeContainer = recipe.ingredients;

Solution

  • You should only be passing one recipe object to your second table view controller (so I don't understand why you're using RecipeObject *recipe = [self.recipes objectAtIndex:indexPath.row] in cellForRowAtIndexPath). You can then use the recipe.ingredients as the array that you use to populate the table. You should still be able to use this line in cellFroRowAtIndexPath,

    cell.textLabel.text = [recipe.ingredients objectAtIndex:indexPath.row];
    

    You should also be passing recipe.ingredients.count to numberOfRowsInSection.

    After Edit:

    Several things are not clear about what you're doing. It seems that you want SecondTableViewController to display a list of ingredients of a single selected recipe from the first controller. So, first of all, there's no need to have the line self.recipes = [RecipeData allRecipes]in SecondTableViewController at all; that controller only needs to know about the one recipe passed in via prepareForSegue. I assume that recipeContainer is an array property of SecondTableViewController that is the array of ingredients; this is what you need to populate your table (BTW, there's no need to pass that in prepareForSegue, since you can get that from the recipe object that you passed). So, the way you should do it is, first, drop the last line you show in prepareForSegue; you don't need it there.

    In SecondTableViewController .h

    @property (strong,nonatomic) RecipeObject *recipe;
    

    In SecondTableViewController .m

    @interface SecondTableController ()
    @property (strong,nonatomic) NSArray *ingredients;
    @end
    
    @implementation SecondTableController
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.ingredients = self.recipe.ingredients;
    }
    
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return self.ingredients.count;
    }
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
        cell.textLabel.text = self.ingredients[indexPath.row];
        return cell;
    }
    

    If you want, you could set the title of SecondViewController in viewDidLoad using self.title = recipe.name