2010/01/14

iPhone : CoreDataレシピ カスタムのプロトコルを作成する。

レシピのAddをpresentModalで行うときに、カスタムのプロトコルを作成して呼び出し元をそれに準拠させておく。

呼出し元クラス(カスタムのプロトコルに準拠)
やること:
1.プロトコルの設定
2.プロトコルメソッドの実装

呼出しクラス(カスタムのプロトコルを定義)
やること:
1.プロトコルの宣言
2.delegateの宣言
3.プロトコルメソッドの宣言



カスタムのプロトコルの使い方
呼出しクラス

やること:
1.プロトコルの宣言
2.delegateの宣言
3.プロトコルメソッドの宣言

//プロトコルの宣言
@protocol RecipeAddDelegate;
@class Recipe;

@interface RecipeAddViewController : UIViewController  {
    @private
        Recipe *recipe;
        UITextField *nameTextField;
//delegateを宣言
        id  delegate;
}

@property(nonatomic, retain) Recipe *recipe;
@property(nonatomic, retain) IBOutlet UITextField *nameTextField;
@property(nonatomic, assign) id  delegate;

- (void)save;
- (void)cancel;

@end


//プロトコルのメソッドを定義
@protocol RecipeAddDelegate 
// recipe == nil on cancel
- (void)recipeAddViewController:(RecipeAddViewController *)recipeAddViewController didAddRecipe:(Recipe *)recipe;

@end


実装部は長いのでいるとこだけ。
プロトコルメソッドを呼び出すだけ、実装はしなくてよい。実装はプロトコルに準拠した呼出しもとクラスで行う。
これでプロトコルを経由して呼出し元のメソッドを呼び出す。

- (void)save {
    
    recipe.name = nameTextField.text;

 NSError *error = nil;
 if (![recipe.managedObjectContext save:&error]) {
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  abort();
 }  
    //プロトコルを経由してメソッドを呼び出す。メソッドの実装は呼出し元で
 [self.delegate recipeAddViewController:self didAddRecipe:recipe];
}





呼出し元

やること:
1.プロトコルの設定
2.プロトコルメソッドの実装

インターフェース
#import "RecipeAddViewController.h"

@class Recipe;
@class RecipeTableViewCell;

@interface RecipeListTableViewController : UITableViewController  {
    @private
        NSFetchedResultsController *fetchedResultsController;
        NSManagedObjectContext *managedObjectContext;
}

@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

- (void)showRecipe:(Recipe *)recipe animated:(BOOL)animated;
- (void)configureCell:(RecipeTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;

@end

実装部
プロトコルのメソッドを実装する。

#pragma mark -
#pragma mark Recipe support

- (void)add:(id)sender {
//ここは呼出しメソッド。ここから呼出しクラスを起動してdelegateする。
    RecipeAddViewController *addController = [[RecipeAddViewController alloc] initWithNibName:@"RecipeAddView" bundle:nil];
    addController.delegate = self;
 
 Recipe *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:self.managedObjectContext];
 addController.recipe = newRecipe;

    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addController];
    [self presentModalViewController:navigationController animated:YES];
    
    [navigationController release];
    [addController release];
}

//プロトコル実装部 dismissModalViewControllerでモーダルを除去する。
- (void)recipeAddViewController:(RecipeAddViewController *)recipeAddViewController didAddRecipe:(Recipe *)recipe {
    if (recipe) {        
        // Show the recipe in a new view controller
        [self showRecipe:recipe animated:NO];
    }
    
    // Dismiss the modal add recipe view controller
    [self dismissModalViewControllerAnimated:YES];
}


- (void)showRecipe:(Recipe *)recipe animated:(BOOL)animated {
    // Create a detail view controller, set the recipe, then push it.
    RecipeDetailViewController *detailViewController = [[RecipeDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
    detailViewController.recipe = recipe;
    
    [self.navigationController pushViewController:detailViewController animated:animated];
    [detailViewController release];
}