Study CoreData 8 ~No Music, No Life~

みなさん、こんちゃ!ばんちゃ!

え〜。既に、このブログの過去約半年でのエントリ数をこの二週間目で上回る勢いのこのシリーズですが、自分も気が乗った時しかこういったコトはしないタチなので、とっても貴重なシリーズになってくると思います(笑)
(現にシリーズのはずなのに続きがないエントリもいくつか…<(_ _;)>ゴメンナサイ…)
 
 
…てなわけで、シリーズ第9回目の『Study CoreData』ですが、
前回までで『Eventの追加とタイトルの入力』までは出来るようになりましたので、いよいよ『詳細ビューの追加』『詳細データの編集機能の追加』に手を染めていきたいと思います。

注意:投稿者自身もCoraDataについて勉強中のため、このシリーズには誤りが含まれている可能性があります。もし、間違いに気付かれた方はコメント欄もしくはtwitterなどでご指摘いただけると幸いです<(_ _)>
また、開発環境はXcode3.2.3 iPhone SDK 4です。実機でのテストなどは自己責任でお願いいたします。

 
 
つまり今回でやっと、基礎的なアプリ構造を完成させることになりそうです。

では、さっそく参りましょう!

1. 詳細ビューを追加する。

まず、詳細ビューのつくりですが、
とりあえず四つの項目を表示して、そこから各項目の編集画面に行けるようにするとしましょう。

こんな感じで。

[AddTitleViewController]と同じように、
UITableViewControllerのサブクラス[DetailViewController]を用意して、これまた同じように次のふたつを加えます。

1. [NSManagedObject]のインスタンスとプロパティの追加と解放。
(名前はmanagedObjectで)
2. 初期化メソッド。
(両方ともAddTitleViewControllerと同じでOKです。)

あとセクション数は1を返せばOKですよね。
で、セクションの行数(numberOfRowsInSection)ですが、
今回は[ManagedObject]のエンティティから全プロパティ(属性と関連両方)を取り出してそのカウントを返すようにしようと思います。
なので、以下のようにしてみてくださいね。

return [[[self.managedObject entity] properties] count];

これでEventエンティティに含まれる全てのプロパティの数が返されるようになります。
(ちなみに属性だけ取り出す場合は、attributesByName。関連だけならrelationshipsByNameです。)
 
 
お次は各セルの表示ですが、ここも今までの内容のおさらい的な感じなので、是非自分でコードを書いてみてくださいね。
ちなみにセルのスタイルはValue2で、表示順は上のシミュレータ画像を参考にしてください。

タタタタタタタ…タ…
(全く関係ないですが、この文章はiPadで書いております(^~^))
 
 
…どうです?できましたかぁ~?

こんな感じでOKかと。

[timeStamp]は編集不可にしたいので、ディスクロージャーインジケータは付けないようにしてあります。
 
 
後は、編集画面から戻ってきた時にちゃんとテーブルビューの表示も更新されるようにするために
[viewWillApper:]でテーブルビューをリロードデータして、一旦[DetailViewController]での作業は完了です!

ここで気付いた方もいらっしゃると思いますが、タイトル編集用のコントローラと今作った詳細表示用のビューコントローラは共通点がありますね。
こういった場合、編集用を詳細表示用のサブクラスにしても良いのですが、今回は共通点以上に相違点(オーバーライドする必要がある箇所)が多いので、継承はしないことにします。

次に、今あるタイトル編集専用のクラスを拡張して、
タイトルだけではなくセクションやアクション名の変更にも対応したクラスを作ります。

2. リファクタリングで一括変換っ!

そこで[AddTitleViewController]という名前のままではおかしいので、
[EditableViewController]に変更したいと思います。
こういった作業をする時のために、Xcodeには[リファクタリング]という便利な機能が備わっています。

使ったコトのない方は、良い機会ですので一緒にやってみましょう。
 
 
まずコード内のどこでも良いので、
変更したい文字列(今回は”AddTitleViewController”)を選択した状態にします。
その状態のまま、⌘+シフト+Jキー
もしくはメニューバーから[編集]-[リファクタリング…]を選択します。

そしてフォーカスされたフィールドに変更後の名称(今回は”EditableViewController”)を入力して[プレビュー]ボタンを押すと、以下のような表示に変わります。

ここで[スナップショット]で現在の状態を保存するかどうかや変更するファイルの選択などができますが、今回はそのまま[適用]ボタンをクリックしてください。
 
すると、コード内の文字列はもちろん、ファイル名も新しい名称に自動的に変更されます。
(ただし、コメントアウトされた部分は変更されないので、気になる方は手打ちで変更してください。)
もし、変更する名称を間違えた場合などは、同時に保存したスナップショットから[復元]出来ます。

ちなみにこの[リファクタリング]は、
今回のようなクラス名の変更以外にも、[変数名]や[メソッド名]などの変更にも使えるので覚えておいて損はないと思いますよ。
 
 
で、ついでに[AddTitleViewControllerDelegate]も
[EditableViewControllerDelegate]に変更してください。
それと、そのデリゲートのメソッドの[- didEditWithViewController: saved:]の第一引数のクラス名も、
[UIViewController]から[EditableViewController]に変更します。

- (void)didEditWithViewController:(EditableViewController *)controller saved:(BOOL)saved;

(両方ともリファクタリングが使えないので、プロジェクト内検索などで。)

これで、新しい編集用コントローラの準備が整いました!
さっそくコイツに手を加えていくとしましょう。

3. 列挙型を使って、ひとつのコントローラで複数のコントローラみたいなフリをさせる(一人三役)

今回、編集の対象となるのは以下の3つですね。

1. [NSString型]の属性[title]の値
2. [NSString型]の関連[action]の属性[name]の値
3. [NSNumber型]の属性[sectionNumber]の値

こういった処理それぞれに対応したい場合、それぞれ別のクラスを用意しても良いのですが、共通点も多いため今回は前述したように[EditableViewController]ですべての処理をさせようと思います。

そのために
『どの値を編集するのか?』
ということを、この新しいコントローラに教えてあげる必要が出てきますよね。
その方法は色々あると思いますが、今回はこんなものを利用したいと思います。
typedef enum {
     EditTypeTitle = 0,
     EditTypeActionName = 1,
     EditTypeSectionNumber = 2
     // EditTypeCreated = 3
} EditType;

実際、これで何をしているかと言うと、
[EditType]という型を作って、その型には
[EditTypeTitle]
[EditTypeActionName]
[EditTypeSectionNumber]

というのが入れられるよ。って決めてます。
(ここでは、”=”の後に整数値を入れていますが、これを書かなくても自動的に整数値が入れられます。今回理由があって入れているので、その説明は後ほど。)

これは、APIの中でもよく使われているもので[列挙型]とか言うらしいです。
ちなみにテーブルビューのスタイルを指定する列挙型はこんな感じ。

typedef enum {
    UITableViewStylePlain,
    UITableViewStyleGrouped
} UITableViewStyle;

これ、めっちゃ便利なのでよく使ってます!

ハツミミな方は是非使ってみると良いですよ〜。
 
 
ってことで、コイツを初期化メソッドの引数にして、
編集する[managedObject]と一緒に受け取るようにしようと思います。
他にも必要なものを用意して[EditableViewontroller.h]は、こんな感じにしてみました。

あと忘れずに、新たなプロパティを@synthesizeするのと、deallocでの解放処理も書いておいてくださいね。
 
 
で、あたらしい初期化メソッドの実装では、
[editType]プロパティをセットして、
さらに[EditTypeSectionNumber]なら[UIPickerView]をテーブルフッタービューとして表示させます。
この際にテーブルビューのスクロールが効いてしまうと、PickerViewの操作が出来ないので、スクロールをDisableにしておきましょう。

コードはこんな感じになりました。

これで、初期化メソッド(イニシャライザ)の変更はOKです。
 
 
次はセルの表示を変更することにしましょう。
[AddTitleViewController]では、直接[tableView:cellForRowAtIndexPath:]内に書いていましたが、[editType]によって処理を分岐したりして多少複雑になるので、今回は別のメソッドを用意してそちらで処理することにします。

これも、前回までのおさらいの部分が多いので、自力でやってみてくださいね。
条件は以下です。

・メソッド名は
[-(void)settingCell:(UITableViewCell *)cell withEditType:(EditType)editType]とします。

・一度に編集(表示)できる項目はひとつ。

・このメソッド内でやることは…
     1. cell.textLabelに、編集する項目(例えば[title]なら”Title:”)を表示させる。
     2. [self.keyString]へ文字列を入れる。(入れるのはkeyもしくはkeyPath)
     3. 各属性のデフォルト値の取得。
     4. textFieldに値を表示。
(デフォルト値と同じ場合はplaceholderとして表示する。
ただし[sectionNumber]はそのままtextField.textで表示)

以上を条件として、各editTypeによって分岐した処理を行います。
 
 
では、れっつとらいっ!

カチャカチャカチャカチャ…
(Macに戻りました)

完成したら、次の画像を見てください。

4. どんな値も文字列に変えてしまう魔法のメソッド


どうでしょう?
見比べてみると、皆さんが書いたものと違っているところがあるはずです。

おそらく、皆さんのコードでは、
3種類のEditTypeそれぞれがif/else文で囲われているんではないでしょうか?

それはそうですよね。
まず、[title]と[action.name]は同じ[NSString型]の値を返しますが
[action.name]を取得するには[valueForKey:]ではなく[valueForKeyPath:]を使わなくてはいけませんし、
[title]と[actionNumber]は共に[valueForKey:]で取得できますが、返される値の型が違います。

…なので、3つのif/elseで処理するのが普通です。
 
 
では、なぜ上のように処理することが可能なんでしょう?

答えは、画像のハイライトされた部分にあります。

[[self.managedObject valueForKeyPath:self.keyString] valueToString];

この[valueToString]ってのが鍵です。
例えば『どんな型の値でも文字列にして返してくれるメソッド』があれば便利だと思いませんか?

そんな便利メソッドを作って、それを利用してるってワケです。
 
 
それでは、そんな便利メソッドの作り方ですが、実装する方法はいくつか考えられますが、今回は[カテゴリ]を使ってみました。

説明します。

今回返される可能性のある型は
[NSString]
[NSNumber](NSUInteger)、
[NSDate]
の3種類ですね。

そこで、使う可能性のある全クラスにカテゴリを追加して、同じ名前のメソッド(今回の例では[valueToString])を実装します。
そこで[NSString型]に変換して返す処理をしてあげれば、ある値を扱う際にこの統一されたメソッドを使うと常に文字列が返されるので、どんな型なのかを意識せずに使えるってワケです。

ちなみに以下のように、カテゴリを作らずにひとつのメソッドで処理する方法も考えられますが、処理速度などを考えるとカテゴリを追加する方が良いかと。

- (NSString *)stringFromValue:(id)value {

	Class classOfValue = [value class];

	if ([classOfValue isKindOfClass:[NSString class]])
		return value;
	else if ([classOfValue isKindOfClass:[NSNumber class]])
		return [NSString stringWithFormat:@"%d", [value intValue]];
	else if ([classOfValue isKindOfClass:[NSDate class]])
		return [NSDateFormatter 
			localizedStringFromDate:value
					dateStyle:NSDateFormatterMediumStyle 
					timeStyle:NSDateFormatterNoStyle];

     return nil;
}

では、早速この3つのカテゴリをとりあえず[EditableViewController.m]のimport文の前後あたりに入れて、[settingCell: withEditType:]を書き換えてください。
(DetailViewControllerでも使えるようにするには、別の場所に入れる必要がありますが今回はそのままでいきます。)
あと、僕が書いたコードとまったく同じにする必要はありません。結果的に同じことが出来ていれば良いので。
とにかく、みなさんが書かれたコードを[valueToString]を使った処理に変えてみてくださいね。
 
 
で、変更が終わったら
そのメソッドを[cellForRowAtIndexPath:]から呼び出せるようにしてあげます。
以前書いたコードは必要ないので消してしまいましょう。

いやぁ〜、随分とすっきりしましたねぇ。
気持ちがいいです(^〜^)

ちなみに今回の処理では[if/else]文が多いせいか、それほど便利だという実感がないかもしれませんが、
この[valueToString]の便利さは後々気付いてくると思いますので。

5. UIPickerViewの設定

お次は[sectionNumber]を編集する際に使う[UIPickerView]の設定に参りましょう。

今回わざわざ[UIPickerView]を使う主な理由は
『アプリ側で定めた規定値以外の値(テキストなど)をユーザが入れられないようにするため』です。
つまり、不要なエラーを起こさせないようにするために使うことにしました。
ですが、もちろん実際のアプリでは他の方法をとることも出来ますので、その辺りは臨機応変にってことで。
今回は簡略化して一番簡単な方法をとることにしました。

こちらもCoreDataとは直接関係しない部分がほとんどなので、コードをのせておきますね。

#pragma mark -
#pragma mark PickerView Delegate & dataSource
- (NSInteger)numberOfComponentsInPickerView:
	(UIPickerView *)pickerView {

	return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView 
	numberOfRowsInComponent:(NSInteger)component {

	return 10;
}

- (NSString *)pickerView:(UIPickerView *)pickerView 
	titleForRow:(NSInteger)row 
	forComponent:(NSInteger)component {

	return [NSString stringWithFormat:@"section: %d", row];
}

- (CGFloat)pickerView:(UIPickerView *)pickerView 
	widthForComponent:(NSInteger)component {

	return 115.f;
}

- (void)pickerView:(UIPickerView *)pickerView 
	didSelectRow:(NSInteger)row 
	inComponent:(NSInteger)component {

	textField.text = [NSString stringWithFormat:@"%d", row];
}

念のため、上のメソッドから順にざっと説明します。

まず、[UIPickerView]のコンポーネント(横の列)の数を返します。
今回は1つですね。

次にそのコンポーネントに何行表示するかを返します。
とりあえず、10を返すようにしました。
これでユーザは0〜9までの間で[sectionNumber]を変更できるようになります。

3つ目のメソッドでは、各行に表示する文字列を返します。
行の上から順に”section: 0″〜”section: 9″と表示されるようにしました。

4つ目はコンポーネントの幅です。
文字列が中心に表示されるように調整した幅を返すようにしてます。

そして最後のメソッドは、
列が選択された(UIPickerViewの回転が止まった)時の処理です。
今回は、選択された時にテキストフィールドの表示を変更するようにしています。
 
 
これで[UIPickerView]の表示内容と選択時の処理が完成しました。
あとは、[sectionNumber]編集時にはキーボードが表示されないようにしておきましょう。

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];

	if (self.editType != EditTypeSectionNumber)
		[textField becomeFirstResponder];
}

それでは、ここまで出来たところで一旦[EditableViewController]での作業を終了して、呼び出す側のクラスに処理を追加していきましょう。
 
 

6. 超シンプルな詳細ビューから各編集ビューへの画面遷移っ!

まずは[DetailViewController]からの画面遷移を追加します。
[DetailViewController.m]の[tableView: didSelectRowAtIndexPath:]に手を付けることにしましょう。
([EditableViewController]のインポートもお忘れなくっ)

『あ〜…ここでも[if]ナントカとか[else if]カントカとかするのかぁ…面倒だなぁ…』

って思った人もいるかもですね^^;

でも、それなら始めっから別々のコントローラを用意した方が良かった気もしますし、メンドくさがりのJacminikはそのようなことはいたしませんっ!(^〜^;)

ホイっ!

上のように、
分岐するのは『編集できるrowなのかどうか?』ってトコだけです。
([timeStamp]は編集不可なので。)

ここで、少し前に用意した[列挙型]に代入していた数字を思い出してみてください。

typedef enum {
     EditTypeTitle = 0,
     EditTypeActionName = 1,
     EditTypeSectionNumber = 2
     // EditTypeCreated = 3
} EditType;

気付きましたか?
ここで明示していた整数は、
実は詳細ビューのindexPath.rowと一致した数値になっていたのです!

じゃじゃ〜ん★

なので、
[EditableViewController]のイニシャライザの[initWithEditType:]に渡す引数に
[indexPath.row]をそのまま渡せば、自動的に各editTypeに変換されるって寸法。
いい感じでしょ?^^;
 
 
それと、デリゲートに[RootViewController]を指定するために、

[[self.navigationController viewControllers] objectAtIndex:0]

としてます。
(もっといい方法があるかもですが…^^;)

あとは、Pushして解放するだけです。

と、これで詳細ビューからの遷移は出来たので、
今度は[RootViewController]の追加ボタンが押された時の処理を変更しにいきましょう。
 
 

追記:RootViewからの遷移もね^^;

…っとその前に、RootViewからDetailViewへの遷移部分を載せていなかったので追記します<(_ _;)>

 
#pragma mark -
#pragma mark Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
	
	DetailViewController *detailViewController = [[DetailViewController alloc] initWithStyle:UITableViewStyleGrouped 
																			  editableObject:selectedObject];
	detailViewController.title = @"Event";
	detailViewController.delegate = self;
	
	[self.navigationController pushViewController:detailViewController animated:YES];
	[detailViewController release];
}

こんな感じで新しい初期化メソッドを使って[title]と[delegate]を設定。
あとはポップすればオッケーですね。

(※twitterでご指摘頂いた@ytさん、ご指摘感謝です!)
 
 

7. [元AddTitleViewController]の跡形をなくす。

追加ボタンを押された時の処理をするメソッドは
[showModalAddTitleView]でしたね。
この中のEditableViewControllerの初期化処理が以前のままですので、新しいイニシャライザに対応させましょう。

(メソッド名や変数名の[Add…]ってのが気になるって方は、例の[リファクタリング]を使って変更してください。)

初期化部分を変更したら
『これが初めての編集処理(新規Event)ですよ』
ってコトが分かるように
[isFirstEdited = YES]
にしておきます。
 
 
そこまでやったら、せっかくですのでビルドしてみましょう。

とりあえず、新規Eventの追加や詳細ビューから各編集画面への遷移は大丈夫そうですかね?
(詳細編集時の保存処理はまだ、変更していないのであしからず。)
[sectionNumber]編集画面が上のキャプチャのように変な感じになってると思いますが、これは後の作業で正常な表示になりますので気にしないでください。

それではXcodeに戻って作業を再開しましょうか。
 
 

8. 保存/キャンセル時の処理を変更する。

保存時の処理を変更しましょう。

[AddTitleViewController]から送られた保存/キャンセル処理をしていたのは
[RootViewController]の[didEditWithViewController: saved:]でしたね。
詳細ビューから編集ビューに移動した場合の保存/キャンセル処理もここですることにします。

新規Eventの場合は、
[Action]エンティティをコンテキストに追加したり、
[timeStamp]や[sectionNumber]の値を自動で入れたりしてましたが、
編集時の場合はすでに[Action]エンティティもありますし、
キャンセルされた時にデータオブジェクトを削除してしまうのはマズイですよね。
ですので、
これらの処理は新規イベント作成時だけ行うようにする必要があります。
 
 
それと、詳細ビューからの編集が終わった後には、
[dismissModalView…]ではなくて[popViewController…]になります。

で、結果的にはこんな風にしておけばOKかと。

新規イベント追加時かどうかは[controller isFirstEdited]で取得できます。

これで保存処理はOKですので、
あとは保存前にデータ[値]を変更させるだけです。
 
 
ってことで、[EditableViewController]に戻りましょう。
[title]の値を変更していたのは[didEditManagedObject:]でしたので、
そこに[sectionNumber]と[action.name]変更時の処理を追加します。

これは特に難しいところはないと思います。

注意しておくのは、
[sectionNumber]の値はちゃんと[NSNumber]に変換するとか、
[action.name]の場合は[forKeyPath:]を使うってコトくらいですかね。

ちなみに[キャンセル]ボタンが押された場合ですが、
テキストフィールドの文字が変更されていたとしても値の変更はされていないので、そのまま保存処理へ送ってしまえばOKです。
(保存する必要もないかもですが、とりあえず^^;)

では、もう一度。

せぇ〜〜のっ!ビルダンゴーーーーーーーーー!!
 
 

9. 念願の…

きましたーーーーーっ!!
ついに念願の『No Music, No Life!』
ちゃんと[sectionNumber]の変更もできてますか?

ただ、セクション番号を変更してもセクションの並び替えが出来てませんねぇ。
(あと、ナビバーにタイトル入れるの忘れてました…<(_ _;)>)

この並び替えは簡単です。
みなさんももうお分かりなんぢゃないでしょうか?
 
 
そう!久々登場のあの方…並び替えの達人、

デーブ・スペク………ソートデスクリプターさんですっ!!
 
 

10. 新しい達人を呼んでくる。

これも、ここまでマスターしてきたみなさんなら朝飯前のはず!
[RootViewController]のプロパティ[fetchedResultsController]内でセットしていた、[NSArray *sortDescriptors]の一番始めのオブジェクトとして

[NSSortDescriptor sortDescriptorWithKey:@"sectionNumber" ascending:YES];

を追加するだけで完了です。
(あと、適当に[RootViewController]と詳細編集時の[EditableViewController]のタイトルを付けといてください。)


  
ふっふふ〜ん〜♬

そろそろ、みなさんもCoreDataの使い勝手が分かってきた感じではないでしょうか?
そうだったらいいなぁと思っています。

実は今回の中で『ユーザビリティ』も考慮したブラッシュアップも考えていたんですが、ちょっと長くなり過ぎてしまったので、それはまた次回。
(その中でUIPickerViewの表示も修正されます。)

それでは、また明日!

しーゆぅねくすとでーぶすぺくた〜〜〜〜〜!
(いちおデーブ風ダジャレってことで^^;)
 

広告

Study CoreData 8 ~No Music, No Life~」への6件のフィードバック

  1. Jacminikさん、初めまして
    このサイトを見ながらまじめにコードを入力して勉強させてもらっている
    ビギナーです。どうしても分からなくなったので質問させて下さい。新規で好きな名前を登録出来、そこから詳細を見に行くのにつまずいてます。
    RootView のdidSelectRowAtIndexPathで
    detailViewController.delegate = self;がエラーになります。これを
    //detailViewController.delegate = self;にしてもDetailが出なくてその上のコードを//editableObject:selectedObject];とすると
    データが入っていない、項目名入りのグループ行が表示されます。
    Detailには初期化メソッドを(study CoreData 6)にある-(id)initWithStyle—、をその通りに書いてます。そこにAlertをいれて試しましたが、そこまで行ってないようです。DetailからEditingには行けて、PickerViewも見れました。さて、私は何が理解できてないのでしょうか?
    ご指導よろしくお願いします。

  2. aonsさん、はじめまして!コメントありがとうございます
    返信が遅くなってしまってすみません

    ご質問のRootViewの[didSelectRowAtIndexPath:]部分のエラーに付いてですが、この[didSelectRowAtIndexPath:]のselectedObject取得直後とDetailViewの[initWithStyle: editableObject:]のif(self = [super…])後の場所に以下のようなログを入れてみてください。

    LOG_CURRENT_METHOD;
    LOG(@”managedObject:%@”, managedObject);
    (※[didSelectRowAt…]の場合はmanagedObjectではなくselectedObjectで。)

    これで各メソッドまで来ているか?managedObjectは正常に代入されているかが分かるはずです。

    これでやってみて[didSelectRowAt…]までは正常に動いていてDetailView側のログが吐かれない場合はメソッド名の記述([didSelectedRowAt…]内かDetailViewのヘッダや実装部)が間違っている可能性があるかもです。

    [editableObject:selectedObject]をコメントアウトして動くということは、[[DetailViewController alloc] initWithStyle:style]には行っているようですね。

    初期化メソッドまで来ているようならmanagedObjectに原因があるかもしれないです。

    このエントリーも手探りながら書いたものなので間違いもあるかと思いますが、また進展がありましたらコメント頂けるとウレシイです。

  3. jacminikさん、返事ありがとうございます。アドバイスの通り
    DetailViewの[initWithStyle: editableObject:]のif(self = [super…])後の場所にNSLogを入れたら、title,sectionNumber,timeStamp全部選択したデータが入ってます。ここまで来てから落ちるのでしょう。
    その後に「*** Terminating app due to uncaught exception’NSUnknownKeyException’, reason: ‘[ valueForUndefinedKey:]: the entity Event is not key value coding-compliant for the key “action.name”.’」と出てエラーになっているようです。
    action.nameが問題なのかと思い、TodoCore2.xcdatamodelを再チェックしても問題はなさそうだし、action.nameは[cell.detailTextLabel.text]にしてますし、そこにはNo Actionと表示されてます。これで何か分かったら教えて下さい。
    よろしくお願いします。

    • そのエラーを見ると簡単にいえば「”action.name”というkeyが見つかりません」ということみたいですね。初期化メソッド内でこのエラーが出るとなると”action.name”がちゃんと保存(取得)されていない可能性が高いです。

      なので”action”を保存している箇所と念のため取得している箇所も全部チェックしてみてください。managedObjectをログ出力してみるとおかしな場所が見つかると思います。
      ちなみに保存/設定時の処理は6章からこの章までに書いてあります。
      取得時は[valueForKey:]ではなく[valueForKeyPath:]です。

      バグ取りは面倒ですが勉強になる部分も多いと思うので^^;
      しつこいようですが記事が間違ってたらごめんなさい<(_ _)>
      また結果をお待ちしてますね。

  4. jacminikさん,笑ってやって下さい。
    結論はDetailViewのcellForRowがvalueForKey:@”action.name”になっててPathが抜けていたことです。SAVEやDetailViewに行くまでが問題だと早合点して重点チェックしてたので、表示部分は見るには見たのですが問題ないよねと軽く飛ばしてたのでした。お恥ずかしい限りです。
    detailViewController.delegate = self;は相変わらずエラーになりますが//つけておいて、新規データ登録、データの変更登録、キャンセルが出来るようになりました。とりあえず先に進みます。お手数をおかけしました。ありがとうございました。

    • いえいえ、笑えませんよっ! 僕も通った道ですから^^;

      今回のバグ取りも良い経験になると思いますし。
      バグを取るにはまず、”どのメソッド内で発生しているのか?”を正確に判別し、さらに”そのメソッドのどこで発生するのか?”を把握して、”何が問題なのか?”を見極める。って事が経験できたんじゃないでしょうか。

      delegateへの代入がエラーになるのはもしかしたら、”delegate”の綴りがどこかで間違っているかもです。(僕はよくやるので^^;)

      また、何か気付いた点などあれば遠慮なくコメントもらえると嬉しいです!

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中