Multiple segues not passing Object data between th

2019-09-18 10:35发布

问题:

I have started a project that was initially completed following Appcoda's tutorial about using view controllers to pass data between scenes (Find it here: http://www.appcoda.com/storyboards-ios-tutorial-pass-data-between-view-controller-with-segue/)

Basically it takes table data from the first scene and the segue connects to another controller that displays the recipe image, prep time, and ingredients. However I wanted to take it one step further and add another view controller that will show the instructions on how to prepare the recipe. So the run down so far is:

Initial View Controller (table data) -> recipeDetailViewController -> instructionsViewContoller

So really just three view controllers but all sharing the same data that. The data I want to share between the view controllers is the recipe data which is in the format:

Recipe *recipe1 = [Recipe new];
recipe1.name = @"Egg Benedict";
recipe1.prepTime = @"30 min";
recipe1.imageFile = @"egg_benedictl.jpg";
recipe1.ingredients = [NSArray arrayWithObjects:@"2 fresh English muffins", @"4 eggs",    @"4 rashers of back bacon", @"2 egg yolks", @"1 tbsp of lemon juice", @"125 g of butter", @"salt and pepper", nil];
recipe1.instructions = @"This is recipe one's instruction set";

and of course this associated code:

self.title = recipe.name;
self.prepTimeLabel.text = recipe.prepTime;
self.recipePhoto.image = [UIImage imageNamed:recipe.imageFile];

NSMutableString *ingredientText = [NSMutableString string];
for (NSString* ingredient in recipe.ingredients) {
    [ingredientText appendFormat:@"%@\n", ingredient];
}
self.ingredientTextView.text = ingredientText;

self.instructionTextView.text = recipe.instructions;

recipeLabel.text = recipeName;

However, when I try tp pass the instructions for the recipe to my third view controller get mixed results. Either nothing gets passed, the latin textField place holder gets passed, or only the recipe.instruction of the first recipe gets passed for all the recipes, no matter what was selected. I have been at this for a week now and think it's time to ask for hope.

If anybody has any suggestions on how to pass my recipe data between multiple segues, I would be much appreciated. I have pasted all my code in below starting with the top files:

//
//  minuteMealsViewController.h
//  minuteMeals
//
//  Created by KMO on 8/18/12.
//  Copyright (c) 2012 KAM Digital. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "Recipe.h"

@interface minuteMealsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) IBOutlet UITableView *tableView;
//@property (nonatomic, weak) IBOutlet UIImageView *thumbnailImageView;



@end

//
//  minuteMealsViewController.m
//  minuteMeals
//
//  Created by KMO on 8/18/12.
//  Copyright (c) 2012 KAM Digital. All rights reserved.
//

#import "minuteMealsViewController.h"
#import "minuteMealsDetailViewController.h"
#import "Recipe.h"

@interface minuteMealsViewController ()

@end

@implementation minuteMealsViewController {
    NSArray *recipes;
    NSArray *thumbnails;
    NSArray *recipeTitle;
}
@synthesize tableView;


//@synthesize thumbnailImageView;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Initialize table data

    Recipe *recipe1 = [Recipe new];
    recipe1.name = @"Egg Benedict";
    recipe1.prepTime = @"30 min";
    recipe1.imageFile = @"egg_benedictl.jpg";
    recipe1.ingredients = [NSArray arrayWithObjects:@"2 fresh English muffins", @"4 eggs", @"4 rashers of back bacon", @"2 egg yolks", @"1 tbsp of lemon juice", @"125 g of butter", @"salt and pepper", nil];
    recipe1.instructions = @"This is recipe one's instruction set";

    Recipe *recipe2 = [Recipe new];
    recipe2.name = @"Mushroom Risotto";
    recipe2.prepTime = @"30 min";
    recipe2.imageFile = @"mushroom_risottol.jpg";
    recipe2.ingredients = [NSArray arrayWithObjects:@"1 tbsp dried porcini mushrooms", @"2 tbsp olive oil", @"1 onion, chopped", @"2 garlic cloves", @"350g/12oz arborio rice", @"1.2 litres/2 pints hot vegetable stock", @"salt and pepper", @"25g/1oz butter", nil];
    recipe2.instructions = @"This is recipe two's instruction set";

    Recipe *recipe3 = [Recipe new];
    recipe3.name = @"Full Breakfast";
    recipe3.prepTime = @"20 min";
    recipe3.imageFile = @"full_breakfastl.jpg";
    recipe3.ingredients = [NSArray arrayWithObjects:@"2 sausages", @"100 grams of mushrooms", @"2 rashers of bacon", @"2 eggs", @"150 grams of baked beans", @"Vegetable oil", nil];

    Recipe *recipe4 = [Recipe new];
    recipe4.name = @"Hamburger";
    recipe4.prepTime = @"30 min";
    recipe4.imageFile = @"hamburgerl.jpg";
    recipe4.ingredients = [NSArray arrayWithObjects:@"400g of ground beef", @"1/4 onion (minced)", @"1 tbsp butter", @"hamburger bun", @"1 teaspoon dry mustard", @"Salt and pepper", nil];

    Recipe *recipe5 = [Recipe new];
    recipe5.name = @"Ham and Egg Sandwich";
    recipe5.prepTime = @"10 min";
    recipe5.imageFile = @"ham_and_egg_sandwichl.jpg";
    recipe5.ingredients = [NSArray arrayWithObjects:@"1 unsliced loaf (1 pound) French bread", @"4 tablespoons butter", @"2 tablespoons mayonnaise", @"8 thin slices deli ham", @"1 large tomato, sliced", @"1 small onion", @"8 eggs", @"8 slices cheddar cheese", nil];

    Recipe *recipe6 = [Recipe new];
    recipe6.name = @"Creme Brelee";
    recipe6.prepTime = @"1 hour";
    recipe6.imageFile = @"creme_breleel.jpg";
    recipe6.ingredients = [NSArray arrayWithObjects:@"1 quart heavy cream", @"1 vanilla bean, split and scraped", @"1 cup vanilla sugar", @"6 large egg yolks", @"2 quarts hot water", nil];

    Recipe *recipe7 = [Recipe new];
    recipe7.name = @"White Chocolate Donut";
    recipe7.prepTime = @"45 min";
    recipe7.imageFile = @"white_chocolate_donutl.jpg";
    recipe7.ingredients = [NSArray arrayWithObjects:@"3 1/4 cups flour", @"2 teaspoons baking powder", @"1/4 teaspoon salt", @"2 beaten eggs", @"2/3 cup sugar", @"2 ounces melted white chocolate", @"1/2 cup milk", nil];

    Recipe *recipe8 = [Recipe new];
    recipe8.name = @"White Chocolate Mocha";
    recipe8.prepTime = @"5 min";
    recipe8.imageFile = @"starbucks_coffeel.jpg";
    recipe8.ingredients = [NSArray arrayWithObjects:@"2/3 cup whole milk", @"6 tablespoons white chocolate chips", @"coffee", @"whipped cream", nil];

    Recipe *recipe9 = [Recipe new];
    recipe9.name = @"Vegetable Curry";
    recipe9.prepTime = @"30 min";
    recipe9.imageFile = @"vegetable_curryl.jpg";
    recipe9.ingredients = [NSArray arrayWithObjects:@"1 tablespoon olive oil", @"1 onion, chopped", @"2 cloves garlic", @"2 1/2 tablespoons curry powder", @"2 quarts hot water", nil];

    Recipe *recipe10 = [Recipe new];
    recipe10.name = @"Instant Noodle with Egg";
    recipe10.prepTime = @"8 min";
    recipe10.imageFile = @"instant_noodle_with_eggl.jpg";
    recipe10.ingredients = [NSArray arrayWithObjects:@"1 pack of Instant Noodle", @"2 eggs", nil];

    Recipe *recipe11 = [Recipe new];
    recipe11.name = @"Noodle with BBQ Pork";
    recipe11.prepTime = @"20 min";
    recipe11.imageFile = @"noodle_with_bbq_porkl.jpg";
    recipe11.ingredients = [NSArray arrayWithObjects:@"1 pack of Instant Noodle", @"BBQ pork", @"Salt and Pepper", nil];

    Recipe *recipe12 = [Recipe new];
    recipe12.name = @"Japanese Noodle with Pork";
    recipe12.prepTime = @"20 min";
    recipe12.imageFile = @"japanese_noodle_with_porkl.jpg";
    recipe12.ingredients = [NSArray arrayWithObjects:@"1 pack of Japanese Noodle", @"2 green onions", @"2 garlic cloves, minced", @"4 boneless pork loin chops", nil];

    Recipe *recipe13 = [Recipe new];
    recipe13.name = @"Green Tea";
    recipe13.prepTime = @"5 min";
    recipe13.imageFile = @"green_teal.jpg";
    recipe13.ingredients = [NSArray arrayWithObjects:@"Green tea", nil];

    Recipe *recipe14 = [Recipe new];
    recipe14.name = @"Thai Shrimp Cake";
    recipe14.prepTime = @"1.5 hours";
    recipe14.imageFile = @"thai_shrimp_cakel.jpg";
    recipe14.ingredients = [NSArray arrayWithObjects:@"8 oz (250g) peeled and deveined raw shrimp", @"2 tablespoons red curry paste", @"1 large egg", @"2 teaspoon fish sauce", @"1 tablespoon sugar", @"2 tablespoons coconut milk", @"2 tablespoons roughly chopped Thai basil leaves", nil];

    Recipe *recipe15 = [Recipe new];
    recipe15.name = @"Angry Birds Cake";
    recipe15.prepTime = @"4 hours";
    recipe15.imageFile = @"angry_birds_cakel.jpg";
    recipe15.ingredients = [NSArray arrayWithObjects:@"12 tablespoons (1 1/2 sticks) unsalted butter", @"2 1/2 cups all-purpose flour", @"1 tablespoon baking powder", @"1 teaspoon salt", @"1 3/4 cups sugar", @"2 large eggs, plus 3 large egg yolks", @"1 cup of milk", nil];

    Recipe *recipe16 = [Recipe new];
    recipe16.name = @"Ham and Cheese Panini";
    recipe16.prepTime = @"10 min";
    recipe16.imageFile = @"ham_and_cheese_paninil.jpg";
    recipe16.ingredients = [NSArray arrayWithObjects:@"2 tablespoons unsalted butter", @"4 cups thinly sliced shallots", @"2 teaspoons fresh thyme", @"1/4 cup grainy Dijon mustard", @"8 slices rustic white bread", @"8 slices Gruyere cheese", @"8 ounces sliced cooked ham", nil];

    recipeTitle = [NSArray arrayWithObjects:@"Egg Benedict", @"Mushroom Risotto", @"Full Breakfast", @"Hamburger", @"Ham and Egg Sandwich", @"Creme Brelee", @"White Chocolate Donut", @"Starbucks Coffee", @"Vegetable Curry", @"Instant Noodle with Egg", @"Noodle with BBQ Pork", @"Japanese Noodle with Pork", @"Green Tea", @"Thai Shrimp Cake", @"Angry Birds Cake", @"Ham and Cheese Panini", nil];


    recipes = [NSArray arrayWithObjects:recipe1, recipe2, recipe3, recipe4, recipe5, recipe6, recipe7, recipe8, recipe9, recipe10, recipe11, recipe12, recipe13, recipe14, recipe15, recipe16, nil];



    thumbnails = [NSArray arrayWithObjects:@"egg_benedict.jpg", @"mushroom_risotto.jpg", @"full_breakfast.jpg", @"hamburger.jpg", @"ham_and_egg_sandwich.jpg", @"creme_brelee.jpg", @"white_chocolate_donut.jpg", @"starbucks_coffee.jpg", @"vegetable_curry.jpg", @"instant_noodle_with_egg.jpg", @"noodle_with_bbq_pork.jpg", @"japanese_noodle_with_pork.jpg", @"green_tea.jpg", @"thai_shrimp_cake.jpg", @"angry_birds_cake.jpg", @"ham_and_cheese_panini.jpg", nil];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [recipeTitle count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @"RecipeCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }
    cell.textLabel.text = [recipeTitle objectAtIndex:indexPath.row];
    cell.imageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];

    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"showRecipeDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

        minuteMealsDetailViewController *destViewController = segue.destinationViewController;

        destViewController.recipe = [recipes objectAtIndex:indexPath.row];
    }
    NSLog(@"showRecipeDetial Segue is being passed");
}

- (void)viewDidUnload
{
    [self setTableView:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
}

@end

//
//  minuteMealsDetailViewController.h
//  minuteMeals
//
//  Created by KMO on 8/18/12.
//  Copyright (c) 2012 KAM Digital. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "Recipe.h"

@interface minuteMealsDetailViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIImageView *recipePhoto;

@property (strong, nonatomic) IBOutlet UILabel *prepTimeLabel;

@property (strong, nonatomic) IBOutlet UITextView *ingredientTextView;

@property (nonatomic, strong) IBOutlet UILabel *recipeLabel;

@property (nonatomic, strong) NSString *recipeName;

@property (nonatomic, strong) Recipe *recipe;

@property (strong, nonatomic) IBOutlet UITextView *instructionTextView;



@end

//
//  minuteMealsDetailViewController.m
//  minuteMeals
//
//  Created by KMO on 8/18/12.
//  Copyright (c) 2012 KAM Digital. All rights reserved.
//

#import "minuteMealsViewController.h"
#import "minuteMealsDetailViewController.h"
#import "Recipe.h"

@interface minuteMealsDetailViewController ()

@end

@implementation minuteMealsDetailViewController

@synthesize recipePhoto;
@synthesize prepTimeLabel;
@synthesize ingredientTextView;
@synthesize recipeLabel;
@synthesize recipeName;
@synthesize recipe;
@synthesize instructionTextView;



- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];


    self.title = recipe.name;
    self.prepTimeLabel.text = recipe.prepTime;
    self.recipePhoto.image = [UIImage imageNamed:recipe.imageFile];

    NSMutableString *ingredientText = [NSMutableString string];
    for (NSString* ingredient in recipe.ingredients) {
        [ingredientText appendFormat:@"%@\n", ingredient];
    }
    self.ingredientTextView.text = ingredientText;

    self.instructionTextView.text = recipe.instructions;

    recipeLabel.text = recipeName;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"showInstructions"]) {

        minuteMealsDetailViewController *destViewController = segue.destinationViewController;

        destViewController.instructionTextView.text = [recipe instructions];

    }
    NSLog(@"showInstructions Seque is being passed");
}


/*- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"showRecipeDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

        minuteMealsDetailViewController *destViewController = segue.destinationViewController;

        destViewController.recipe = [recipes objectAtIndex:indexPath.row];
    }
    NSLog(@"showRecipeDetial Segue is being passed");
}*/

- (void)viewDidUnload
{
    [self setRecipePhoto:nil];
    [self setPrepTimeLabel:nil];
    [self setIngredientTextView:nil];
    [self setInstructionTextView:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end

//
//  Recipe.h
//  minuteMeals
//
//  Created by KMO on 8/19/12.
//  Copyright (c) 2012 KAM Digital. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Recipe : NSObject

@property (nonatomic, strong) NSString *name; // name of recipe
@property (nonatomic, strong) NSString *prepTime; // preparation time
@property (nonatomic, strong) NSString *imageFile; // image filename of recipe
@property (nonatomic, strong) NSArray *ingredients; // ingredients
@property (nonatomic, strong) NSString *instructions; // instruction set

@end

//
//  Recipe.m
//  minuteMeals
//
//  Created by KMO on 8/19/12.
//  Copyright (c) 2012 KAM Digital. All rights reserved.
//

#import "Recipe.h"

@implementation Recipe

@synthesize name;
@synthesize prepTime;
@synthesize imageFile;
@synthesize ingredients;
@synthesize instructions;

@end

回答1:

Try to set the instruction as it own property first and set the label in viewDidLoad

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"showInstructions"]) {

        minuteMealsDetailViewController *destViewController = segue.destinationViewController;

        destViewController.instructionText = [recipe instructions];

    }
    NSLog(@"showInstructions Seque is being passed");
}

Where instructionText is a new property.

and in viewDidLoad for your instructionsViewController do

instructionTextView.text = self.instructionText;

Edit:

The reason why you are not seeing anything is that the view is not completely loaded in prepareForSegue and all the initialization of the views should be in viewDidLoad. That method is called when it safe to change your views.

You are now using the same viewcontroller for both the "recipeDetail" and "instructions" I would recommend having a separate viewController class for you instructions.

And simply pass your instructions as a property in that viewController.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"showInstructions"]) {

        MinuteMealsInstructionsViewController *destViewController = segue.destinationViewController;

        destViewController.instructionText = [recipe instructions];

    }
    NSLog(@"showInstructions Seque is being passed");
}

where MinuteMealsInstructionsViewController is the new class with the instructions property.

You say that you want to keep the recipe contained within the recipe object. And this is still true since you are only passing references to the object members. Let's say you change the instructions string then it will also change in your recipe object since the string is only a reference.

On a side note: You should use start your class names with a capital letter according to the Objective-c style guides.

If you really want to do it within the same viewController you could simply pass the whole recipe object destViewController.recipe = recipe; and in viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.instructionTextLabel = recipe.instructions;
}