Study CoreData 13 ~ 鱗 ~

いやぁ〜。もう7月も後半に入ってきましたね〜。

夏と言えば『海』!『花火』!!
そして…
 
 
『ひと夏のあばんちゅ〜♡』
 
 
…。

ま、妄想過多な感じでもんもんとしつつ、本日もスタートです\(>〜<;)/

キャンプファイアとかでドキドキしたいなぁ…

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

 
 
前回は“安全性の高いデータの受け渡し”を実装して、次に保存処理を…
ってトコまででしたね。

では、今日も[dotodo]プロジェクトを開いて始めて行くとしましょう!
 
 

1. データの保存 改良版

前回、保存/キャンセル時の処理の仕方として、

『キャンセル時は新しいコンテキストを削除するだけ』
『保存時には、新しいコンテキストを保存して大もとのコンテキストと合成する。』

って書きました。
でも、[RootViewController]にデータが返されるのは[保存時]、[キャンセル時]の他にもうひとつあります。
 
 
そう!
『データ削除時』です!

以前『TodoCore』の[didEditWithViewController: saved:]でもやったように、データ削除時には“managedObjectを削除して保存する”んでしたね。

つまり、新しいバージョンでのデータ削除は、
provisionalContextを削除 + [masterTask]を削除

この2つを実行する事になりそうですね。
ってことは、[didSelectRowAtIndexPath]で取得した[masterTask]データ削除にも参照出来るようにしたいので、masterTaskをヘッダファイルで宣言しときましょう。


 
 
そしたら、先にデリゲートプロコルを用意するために、[EditValueController.h]に戻ります。

今回は、新しい[列挙型]を用意して
それをデリゲートメソッドの引数に使う事で、保存/キャンセル/削除それぞれの処理に対応させることにしました。
 
 
お次ぎはいよいよデリゲートメソッドの実装です。

2. デリゲートメソッドの保存処理


 
2つのメソッドがありますが、先に下のデリゲートメソッドから説明します。

保存時の処理以外は、今までの説明で分かると思うので割愛させてもらいます<(_ _)>
それと、メソッドの最後のところで保存状態に関わらず
一時的なコンテキストと[_masterTask]をnilにしているトコロにも注意してください。
 
 
保存時、コンテキストを保存する前に
[defNotification]と言う通知用のオブジェクトを作っています。

これをしておく事で、

[object:context]
[name:NSManagedObjectContextDidSaveNotification](保存された)時に、
[addObserver:self]
[selector:@selector(provisionalContextDidSave:) ]に通知

されるようになります。
※このときに渡されている[context]は[_provisionalContext]です。

つまり、この場合では
“if (![context save:&error])”の後に“provisionalContextDidSave:”
が呼ばれるわけです。
 
 
そしてその呼びだし先の[provisionalContextDidSave:]では

大もとの[manadedObjectContext]を取得して、
[mergeChangesFromContextDidSaveNotification:]を使って
Notificationに渡された[provisionalContext]と
大もとの[managedObjectContext]を合成しています。

これで、編集/追加されたデータが確実に更新されました!

あとは[removeObserver:]で後片付けすれば完了です。
 
 
まぁ、ノーティフィケーションについては、ここで深く突っ込んでいくとドツボにハマりそーなので、こんな風に使えば安全に保存処理を完了できるんだな
ってくらいにしときます^^;
 
 
これでRootViewでの保存の処理はなんとか出来た感じなので、お次ぎはDetailtViewの表示とデータの受け渡しを作りにいきましょう!
 
 

3. Simple is BEST !!

まずは、今回も完成イメージを見てみましょう。

DetailViewに必要な要素

*セクション数は3

*各セルに必要な要素は…

  ・セルのタイトル
  ・文字列化した各値
   もしくはコントロールオブジェクト
  ・値を取得するためのKey
  ・値がnilの時に表示する文字列

*状態によるViewの変化

  ・保存関連ボタンの表示/非表示
  ・削除ボタンの表示/非表示

 

で、改めてセルの表示について考えてみると
まさか、各セルすべてをSwith文で分けるのか?!(・□・;)
ってことになりますわな〜、当然。

 
でも、こうゆう“報われそうもない努力”的なものって、出来るだけ避けたいと思うのが人情でして…^^;

まぁ、[priority]と[completed]は各コントロールを表示しなきゃいけないので、分岐させるのは仕方ないとしても、似てるように見える
テキストだけを表示しているセルは分岐せずに表示できないのか?
って思っちゃうんですよね。
 
 
…で、それを解決する”目から鱗”な方法を発見致しました!隊長っっ!!
(僕が考えたものではありませんが^^;)
 
これを見て『ピンと来た!』って方はそーとー勘が良い方だと思いますが、そうじゃない方も多いと思うので説明しますね。
 
 
一番上にある[_valueTitles]の初期化の部分に注目してみてください。

この[_valueTitles]はNSArray型のプロパティとして宣言してあります。
そしてその[_valueTitle]の中でさらに3つのNSArrayが入れ子になってますね。
 
 
…で、たとえばコメントしてあるsection番号を見ると分かるように
Section:0 の Row:2の[Tag]を表示するセルの場所には@”Tag:”というタイトルが入れられています。

つまり、
[_valueTitles]の中の各Arrayがセクションになっていて、
そのArrayにはそれぞれのRowに対応するオブジェクトが入れられている
ってワケです!

まったくステキすぎっ!!
 
 
ですが、これだけではindexPathを使って取り出せないので、
NSArrayにカテゴリを追加します。

渡されたindexPathによってsubArrayの中のオブジェクトを取り出す。
たったこれだけです。

これで

[_valueTitles objectAtIndexPath:indexPath];

って書くだけで勝手に各セルに対応したタイトルが入れられるようになります!
 
※この情報は、『More iPhone 3 Development』(Dave Mark, Jaff LaMarche 著)と
同書を使った学習として書かれた以下のブログを参考にさせて頂きました<(_ _)>

Core Data 勉強日記 – Natsu’s iPhone App
 
 

4. 便利Arrayを使ってみる

まず、先程の”NSArrayのためのカテゴリ”(objectAtIndexPath:)を[DTDValueCategorys]に入れておきます。
(宣言も忘れずに!!)

そして、その前に紹介したメソッド[setConvenientArrays]の実装も
“DetailViewController.m”の初期化メソッドの下辺りに入れましょう。

そしてそれを[ViewWillApper:]で呼び出しておきます。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
	
	[self setConvenientArrays];
}

 
それと念のため“Task.h”をインポートしてあるのを確認して、ついでに
“EditableViewController.h”
“SelectableViewController.h”もインポートしときます。
※DTDValueCategorysは”Task.h”でインポートされているので、ここではインポートなしで使えます。
 
そこまで出来たら[tableView: cellForRowAtIndexPath:]で、cellStyleを“UITableViewCellStyleValue2”にして、section:0の場合の表示をコーディングしてみてください。
書き終わったら下の画像と確認してみてくださいね。
 
 
 

どうでしょう?
こんな感じになったでしょうか?

ここまでやってきたみなさんにはほぼ説明無用ですかね?
一応、valueがnilもしくはデフォルト値と同じの場合には、
テキストをグレーで表示させてます。

で、textLabelの方はsection:1、2でも同じように表示するので、if文の外に書いてます。
 
 
そして、section:1、2の方の表示はこんな感じで。

	else {
		if (indexPath.section == 1) {				
			_priorityControl = [[UISegmentedControl alloc] initWithItems:
								[NSArray arrayWithObjects:
								 [UIImage imageNamed:@"Priority_0.png"],
								 [UIImage imageNamed:@"Priority_1.png"], 
								 [UIImage imageNamed:@"Priority_2.png"],
								 [UIImage imageNamed:@"Priority_3.png"], 
								 nil]];
			
			_priorityControl.frame = CGRectMake(87.f, 6.f, 205.f, 32.f);
			_priorityControl.segmentedControlStyle = UISegmentedControlStyleBar;
			
			_priorityControl.tintColor = [UIColor colorWithRed:0.8f green:0.6f blue:0.1f alpha:0.6f];
			
			[_priorityControl addTarget:self 
								 action:nil 
					   forControlEvents:UIControlEventValueChanged];
			
			_priorityControl.selectedSegmentIndex = [_editableObject.priority intValue];
			
			[cell.contentView addSubview:_priorityControl];
			[_priorityControl release];
		}
		else if (indexPath.section == 2) {
			_compSwitch = [UISwitch new];
			_compSwitch.frame = CGRectMake(198.f, 8.f, 0, 0);
			[_compSwitch addTarget:self 
							action:nil
				  forControlEvents:UIControlEventValueChanged];
			
			_compSwitch.on = [_editableObject.completed boolValue];
			[cell.contentView addSubview:_compSwitch];
			[_compSwitch release];
		}
		
		cell.selectionStyle = UITableViewCellSelectionStyleNone;
	}

※各コントロールの”action”は、まだ用意していないので[nil]にしてあります。
 
こちらではセルは選択できないので、アクセサリは無しにしてます。
(その他UIKit関連の説明は割愛させて頂きますです<(_ _)>)
 
 
ってなわけで、次は[didSelectRowAtIndexPath:]に進むのですが
それはまた次回。
 
 
みなさま、
今回の『Study CoreData』はいかがだったでしょうか?
 
 
今回は、安心設計の保存処理目から鱗のTipsなどそれなりに濃い内容だったんじゃないかなぁ?なんて思ってます。

まぁ、[TodoCore]を使った勉強である程度CoreDataの使い方は分かってきていると思うので、より実践に近いやり方として
『CoreData 6:その他Tips等 4』くらいの割合で進めていく感じになるかもしれませんね。
 
 
何はともあれ、開発も勉強も遊びもほどよく楽しんでいきましょう!

それでは、またあした。
 
 
あでゅ〜〜♬

広告

Study CoreData 13 ~ 鱗 ~」への1件のフィードバック

  1. ピンバック: [夕刊] @kazuend 徹底インタビュー記事が公開される。

コメントを残す

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

WordPress.com ロゴ

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

Twitter 画像

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

Facebook の写真

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

Google+ フォト

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

%s と連携中