トップページ | 2010年7月 »

2010年6月

2010年6月24日 (木)

iphone 開発 サンプル「CoreDataBooks」を読む。3

iphone 開発 サンプル「CoreDataBooks」を読む。3

「概要」
サンプル「CoreDataBooks」を読む。2のつづき。

iphoneアプリの開発者向けサイトのサンプル「CoreDataBooks」を参照する。
ソースを読んだ時系列にメモしていくので、疑問点(?)などもそのままかいている。
以下の文は、CoreDataBooksを読もうとしている人以外には、情報がないと思う。
また、間違いもたくさんあると思う。鵜呑みにしないようにご注意を。

「今回の目的」
UndoManagerを理解する。

DetailViewControllerに出てくるundo系の操作は何をしているか。
たぶんキャンセル時など、ユーザの入力をなかったことにしているのでは。
仕組みがよくわからない。

リファレンス「Introduction to Undo Architecture」を読む。

操作を取り消しできる。
取り消しができるということは、やり直し(取り消しの取り消し)もできるということ。

操作はundo groupsに集められる。取り消しはグループ単位で行われる。
取り消したい単位でグループを作成すること。

undoとredoはそれぞれにstackをもつ。
最初は両方からっぽ。
そのあとはいろいろと増えたり減ったり。

undo stackにpushする方法は2つある。
"Simple undo"
 変更があったとき、そのオブジェクトが変更をマネージャに登録する。
 一つの引数しか持てない。

"Invocation-based undo"
 NSInvocationを使う。
 引数をいくつでも持てる。

うーん、難しい。

ネットで調べてみる。非常にわかりやすい解説がある。
http://journal.mycom.co.jp/column/objc/095/index.html
http://xcatsan.blogspot.com/2008/05/rubberband19undo-nsundomanager.html

要点は、
・何か操作を行うとき、それを元に戻す操作を登録する。(undo stackへのpush)
・取り消しが行われたとき、
 1.undo stackの操作がpopされ実行される。
 2.「1.」への取り消しがredo stackにpushされる。
で、redoが行われたときは、redoからpop実施され、その取り消しがundoにpushされるはず。

ちょこっと知識が増えたので、もう一度ソースを見る。

DetailViewControllerのメソッドsetUpUndoManagerでNSUndoManagerが生成されている。
そこでNSNotificationCenterに、undo/redo実施時に呼び出すメソッドをひもづけている?

また知らないクラスが出てきた。NSNotificationCenter。保留。

undo/redo実施の通知を受けたら、テーブルビューをリロードして、右のボタンを制御仕手いる模様。

undo/redoはどこで実施されるのか?

EditingViewControllerのメソッドsaveで、setActionNameで、アクション名を登録している。
が、これが使われる場所がわからない。

DetailViewControllerのundoManagerDidUndoとundoManagerDidRedoに
デバッグポイントをおいて実施してみたが、
何をやってもひっかからなかった。undoのあたりのオペレーションは正常系では実施されないのかも。

今回はここまで。

追記)実は編集からSaveをした後、シェイクでUndo/Redoする模様。
でもそうなる理由はよくわからない。

追記)iphone 開発 サンプル「Simple Undo」を読む。を追加しました。
こちらを読むとCoreDataBooks側も理解できるかもしれません。


| | コメント (0) | トラックバック (0)

2010年6月23日 (水)

iphone 開発 サンプル「CoreDataBooks」を読む。2

サンプル「CoreDataBooks」を読む。2

「概要」
サンプル「CoreDataBooks」を読む。1のつづき。

iphoneアプリの開発者向けサイトのサンプル「CoreDataBooks」を参照する。
ソースを読んだ時系列にメモしていくので、疑問点(?)などもそのままかいている。
以下の文は、CoreDataBooksを読もうとしている人以外には、情報がないと思う。
また、間違いもたくさんあると思う。鵜呑みにしないようにご注意を。

「今回の目的」
各ViewControllerの関係を理解する。


AddViewControllerは、DetailViewControllerを継承している。
また、AddViewControllerは、インスタンス変数にid を持っている。

これはどういうことか。

まず、上記delegateには、RootViewControllerがセットされる。
AddViewControllerでcancelまたはsave時に下記メソッド呼び出しを行う。
addViewController:didFinishWithSave:
これは、AddViewController.hで定義されたプロトコルの要請するメソッド。
このプロトコルに準拠するRootViewControllerは、ヘッダで、AddViewControllerDelegateに従うことを宣言し、メソッドを実装している。

RootViewControllerのメソッドaddViewController:didFinishWithSave:を見る。
ここでCore Data関連のやり取りがあり、コンテキストのsaveが行われる。

delegateにしている理由は、Core Data関連の処理を、RootViewControllerで行いたいから?
それぞれのビューで行うとしたら、関連インスタンス変数を持ち回らないといけない。

AddViewControllerとDetailViewControllerのUIの違いをそれぞれのviewDidLoadメソッドで吸収している。

EditingViewControllerではNSManagedObject *で情報を持ち、DetailViewControllerでは、Book *で情報を持つ。
BookはNSManagedObject を継承しているので、EditingViewControllerもBook *で情報を持てば良いのでは?

EditingViewControllerのNSManagedObjectをBookに変えてみる。
→問題なく動いた。Bookの方がsetValue:forKey:を使わなくても、直接プロパティを操作できてよいかも。

今回は以上

| | コメント (0) | トラックバック (0)

iphone 開発 サンプル「CoreDataBooks」を読む。 1

サンプル「CoreDataBooks」を読む。

「概要」
iphoneアプリの開発者向けサイトのサンプル「CoreDataBooks」を参照する。

ソースを読んだ時系列にメモしていくので、疑問点(?)などもそのままかいている。

以下の文は、CoreDataBooksを読もうとしている人以外には、情報がないと思う。

また、間違いもたくさんあると思う。鵜呑みにしないようにご注意を。

「ファイル構成」
CoreDataBooksAppDelegate.{h,m}
Core Data Stackと、最初のview controllerを設定する。

RootViewController.{h,m}
本のテーブルビューを管理する。本の追加と削除を提供する。

DetailViewController.{h,m}
1つの本の詳細表示を管理する。

AddViewController.{h,m}
新規の本オブジェクトを管理するための、DetailViewControllerのサブクラス

EditingViewController.{h,m}
データを編集するためのビュー

Book.{h,m}
本を表現するmanaged object クラス

CoreDataBooks.sqlite
データベース。初回起動時に適切な場所にコピーされる。

CoreDataBooks.xcdatamodel
Core Data managed object model

「継承関係」
RootViewController : UITableViewController
全タイトルをリスト表示するため、テーブルビューコントローラ
DetailViewController : UITableViewController
タイトル/著者/コピーライトをリスト表示するため、テーブルビューコントローラ
AddViewController : DetailViewController
EditingViewController : UIViewController
 タイトル/著者/コピーライトのいずれかを入力する単票画面

「ヘッダファイルの特徴」
RootViewController.h
CoreData関連のプロパティが多数。外からこれらを操作するのか?
メソッド:addBookがある。本を追加したときどう処理するのか?

DetailViewController.h
プロパティ:Bookがある。詳細表示する本をもつ。ここに値をいれるのはいつ、どうやって?
NSUndoManagerがある。何をUndoするのか?

AddViewController.h
AddViewControllerDelegateプロトコルを実装するdelegateクラスをもつ。
これはメソッド:addViewControllerの実装を要求する。このメソッドの中身は?

EditingViewController.h
 編集用の入力フィールドを持つ。
 NSManagedObjectを持つ。これをだれが、いつ、どのように操作するか。
 メソッド:cancel,saveを持つ。saveでcore data関連オブジェクトへのアクセスが行われる?

Book.h
タイトル、著者、コピーライトを保持する。

CoreDataBooksAppDelegate.h
ここにもRootViewController.hと同じようなCoreData関連のプロパティが多数。関連は不明

比較する。
CoreDataBooksAppDelegate.h)
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;

RootViewController.h)
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
NSManagedObjectContext *addingManagedObjectContext;


「処理」
まず、初期化処理

○CoreDataBooksAppDelegate.m

メソッド:applicationDidFinishLaunchingにRootViewControllerの
managedObjectContextセット処理がある。同じものを共有している模様。

navigationControllerのトップビューとして、RootViewControllerをセットする処理は、
MainWindow.xibで行っているため、ソースにはセット処理はない。

上記CoreData関連のゲッターでオブジェクトの初期化処理があり、Contextにsqliteのデータを
ひも付けしている模様。

Context と、Persistent object と、Fetchの関係がよくわからない。
「 Core Data Programming Guide」を読む。

Fetchによって、Persistent objectが Context にロードされるらしい。

○RootViewController.m
メソッド: viewDidLoadでデータのフェッチを行っている模様。
fetchedResultsControllerの初期化はどこ?
→fetchedResultsControllerのゲッターで行っている。
 ここで取り出すエンティティとソート順を決めている。

画面への表示部分は、メソッド:configureCellにより、fetchedResultsControllerから情報を取り出している。

詳細画面への遷移は、メソッド:tableView:didSelectRowAtIndexPath:のところ。該当する本をフェッチ結果から取得して渡している。

○DetailViewController.m
タイトル/著者/コピーライトの3つをリスト表示している。
undoManagerの使われ方がわからない。持ち越し。
メソッド:tableView:didSelectRowAtIndexPath:で、どの要素を編集するか決定し、EditingViewControllerに遷移する。
その際、editedObjectをセットしている。これにより、本の情報を渡している。

○EditingViewController.m
メソッド:saveにより、editedObjectを修正している。これにより、呼び出し元に情報が渡される。
popViewControllerAnimatedで、画面をもとに戻す。

今のところ、メモリ(Context)上の変更だけで、ファイルへの書き込みはまだだと思う。

○RootViewController.m
メソッド:addBookでAddViewControllerを生成し、遷移する。delegateにselfを渡している。
何かRootViewControllerの持っているメソッドを実施する模様。
別のcontext(addingManagedObjectContext)が必要な理由がわからない。

と思ったら、メソッド:addViewController:didFinishWithSaveにコメントで説明が。
翻訳)
新規の本は新規のコンテキストと関連していんだ。
これはメインのコンテキストへの影響を与えない点で良いことだ。
しかしこのことは、新規の本をフェッチコントローラから取得することを困難にするんだ。
まず、新規の本をsaveしよう。これで永続的なストアに追加されるんだ。

今日は、ここまで


それで、アプリケーションのデリゲートコンテキストにmanaged objectを取って入れることができるんだ。

(やり方の例)

ただ、このやり方だと、変更通知を監視しているフェッチ結果コントローラを更新しない。
あなたは負荷の高いフェッチのやり直しを望んでいない。
あなたは、メインコンテキストの更新をmergeChangesFromContextDidSaveNotificationで行うことができる。


| | コメント (0) | トラックバック (0)

トップページ | 2010年7月 »