|
|
Log In | Not a Member? |
Contact ADC |
この文書では、アプリケーションにおける管理対象オブジェクトの使用と操作に関連する問題について説明します。
管理対象オブジェクトの変更
メモリ管理
コピーとペースト
検証
関係とフォールト
データの確実な更新
管理対象オブジェクトのプロパティを変更するには、デフォルトでは、(管理対象オブジェクトモデルで定義した)プロパティの名前をキーとしてキー値コーディングを使用します。この一般原則は属性と関係の両方に適用されます。対多関係については、後で説明するように、特に考慮すべき事柄がいくつかあります。
以下の例では、単純な属性の変更について示します。対一関係の変更にも同じテクニックを適用できます。
|
特定エンティティのカスタムクラスを定義し、独自のアクセサメソッドを実装した場合は(実装の詳細については、『NSManagedObject』の「Subclassing Notes」を参照)、以下の例に示すように、それらを直接呼び出すことができます。
|
もちろん、カスタムクラスとカスタムアクセサを指定した場合も、キー値コーディングが使えます。
対多関係を変更する場合も、キー値コーディングを使いますが、mutableSetValueForKey: を使用します。このメソッドは、関係を変化させ、適切なキー値監視通知を送るという 2 つの処理を行うプロキシオブジェクトを返します。通常は、対多関係を対象に独自のコレクションアクセサメソッド(add<Key>Object: および remove<Key>Object: など)を実装するべき理由はほとんどありませんが、実装した場合はこれらを直接呼び出すことができます(カスタムアクセサを実装する場合は、注意して add<Key>Object: と remove<Key>Object: のペア、または add<Key>: と remove<Key>: のペア、あるいは両方のペアを実装する必要があります。そして、これらが、関連する KVO 通知を確実に送るようにします。実装の詳細については、『NSManagedObject』の「Subclassing Notes」を参照してください)。関係変更の詳細については、「関係の操作」を参照してください。
一般に、管理対象オブジェクトを使用する際は、標準の Cocoa メモリ管理ガイドラインに従いましょう。ただし、考慮すべき問題がいくつかあります。
メソッド名に「new」という語が含まれているもかかわらず、NSEntityDescription の簡易メソッド insertNewObjectForEntityForName:inManagedObjectContext: は自動リリースオブジェクトを返します。これは、そのメソッドがレシーバ(またはそのサブクラスの 1 つ)ではなく、別のクラスの新しいインスタンスを作成するからです。
管理対象オブジェクトはその管理対象オブジェクトコンテキストへの参照を持っており、逆もまた同様です。しかし、保持(retain)の循環を避けるために、デフォルトでは、どちらのオブジェクトも他方を保持しません。つまり、コンテキストを作成し、管理対象オブジェクトをそのコンテキストに割り当てる場合は、コンテキストと管理対象オブジェクトの両方を適切に保持する必要があります。
ただし、前述の記述にもかかわらず、変更(挿入、削除、または更新)が保留されている管理対象オブジェクトは、コンテキストに save:、reset、rollback、または dealloc メッセージに送られるまで、または関連する変更がアンドゥされるまでは、それらのコンテキストによって保持されます。
管理対象オブジェクトコンテキストに関連付けられているアンドゥマネージャは、変更のあった管理対象オブジェクトをすべて保持します。さらに、デフォルトでは、コンテキストのアンドゥマネージャは無制限のアンドゥ/リドゥスタックを維持しています。したがって、メモリの問題を避けるために、適宜(たとえば、保存操作の後に)、アンドゥスタックをリセットするべきです。別の方法で保持していないかぎり、コンテキストのアンドゥマネージャは、そのコンテキストへの割り当てを解除します。
コンテキストに対して管理対象オブジェクトを保持するように指定するには、setRetainsRegisteredObjects: メッセージに引数 YES を渡してコンテキストに送ります。
管理対象オブジェクトと別の管理対象オブジェクト(または他の管理対象オブジェクトのコレクション)との間の関係は、保持が行われることを意味します(対多関係の場合は、すべての対象オブジェクトが保持されます)。これは保持の循環をもたらす可能性があります。このような保持の循環を断ち切るには 3 つの方法があります。
オブジェクトをリフレッシュします(管理対象オブジェクトコンテキストに refreshObject:mergeChanges: メッセージを送ります)。これによってオブジェクトがフォールトになり、それらの関係が断ち切られます(その結果、対象オブジェクトが解放されます)。
管理対象オブジェクトコンテキストをリセットします。
管理対象オブジェクトコンテキストを解放します(これによってコンテキストの割り当てが解除されることを前提とします)。
これらの操作によって管理対象オブジェクトがフォールトになり、対象オブジェクトが解放されます。
管理対象オブジェクトコンテキストをロックした場合(すなわち、正常に tryLock できた場合)は、ロック解除を呼び出すまで、ロックを発動したスレッドでコンテキストを保持きるようにする必要があります。マルチスレッド環境でコンテキストを適切に保持しないと、デッドロックが発生します。
留意すべきもう 1 つの問題は、ビュー(またはコントローラ)オブジェクトが一般的に、表示(または管理)するオブジェクトを保持するということです。これが特に関連するのは、NSController のサブクラスがそれらのコンテンツオブジェクトを保持する Cocoa バインディングを使用する場合です。
管理対象オブジェクトのコピーとペーストに関する問題を一般的な方法で解決するのは困難です。オブジェクトグラフのどの部分を実際にコピーするのかを、ケースバイケースで判断する必要があります。
多くの場合は、コピー時に管理対象オブジェクトを表すディクショナリ(プロパティリスト)を作成し、ペースト時に新しい管理対象オブジェクトを作成し、ディクショナリを使用して内容を設定するのが最善策です。例については、『NSPersistentDocument Core Data Tutorial』を参照してください。
管理対象オブジェクトモデルでは、プロパティが持ちうる値に制約を設けることができます(たとえば、Employee の給与はマイナスにできないとか、どの従業員も Department に所属しなければならないというような制約です)。
validateForUpdate: を使用すれば、こうした制約がすべて満たされているかどうかを確認することができます。1 つの操作に複数の検証エラーがある場合、それらのエラーは userInfo ディクショナリの配列に集められます。そこからエラーを取り出すには、NSDetailedErrorsKey キーを使用します。
管理対象オブジェクトは新しい値と、モデルに指定されている制約を比較します。
また、validateValue:forKey:error: を使用して、個別の値を検証することもできます。たとえ validate<Key>:error: という形式のカスタム検証メソッドを実装した場合でも、通常はカスタム検証メソッドを直接呼び出すべきではありません。その代わりに、適切なキーを指定して validateValue:forKey:error: を呼び出すようにします。これにより、管理対象オブジェクトモデルに定義されている制約がすべて確実に適用されます。
管理対象オブジェクトは通常、永続ストアに保管されているデータを表します。ときには、管理対象オブジェクトが「フォールト」(プロパティ値が外部ストアからまだロードされていないオブジェクト)であることもあります。永続プロパティ値にアクセスすると、フォールトが「発動」し、その永続データがストアから自動的に取り出されます。状況によっては、管理対象オブジェクトを明示的にフォールトに変えることも考えられます(通常は、NSManagedObjectContext の refreshObject:mergeChanges: を使用して、値を最新の状態にすることを目的とします)。もっと一般的には、関係を渡り歩いているときにフォールトに遭遇します。
管理対象オブジェクトを受信しても、Core Data は関係の対象となっている他のオブジェクトに関するデータを自動的には受信しません(「フォールティング」を参照)。最初、オブジェクトの関係はフォールトで表されます(対象オブジェクト自体がすでに受信されていないかぎり−「一意化」を参照)。しかし、関係の対象オブジェクトにアクセスすると、それらのデータが自動的に取得されます。たとえば、アプリケーションを初めて起動したときに、永続ストアから Employee オブジェクトを 1 つ受信すると、(以降のものが永続ストアにあると仮定して)その manager および department 関係はフォールトとして表されます。それでも、次のコード例に示すように、従業員の上司のラストネームを要求することができます。
|
あるいは、もっと簡単に、キーパスを使用します。
|
この場合は、対象 Employee オブジェクト(上司)のデータが自動的に取得されます。
ここに微妙ながらも、重要なポイントがあります。なお、関係を渡り歩くために(この例では、従業員の上司を見つけるために)、関連オブジェクトを明示的に受信する必要はありません(すなわち、受信要求の作成と実行はしません)。単にキー値コーディング(あるいはアクセサメソッドを実装していれば、それら)を使用して 1 つまたは複数の対象オブジェクトを取得するだけで、Core Data によって関連オブジェクトが自動的に作成されます。たとえば、従業員の上司の上司の部署名は次のように要求することができます。
|
(もちろん、これは従業員が管理階層の少なくとも 2 つ下のレベルにいるという前提です。)また、コレクション操作メソッドを使用することもできます。従業員の部署に関する給与オーバーヘッドは次のようにして見つけることができます。
|
多くの場合、最初の受信でオブジェクトグラフの開始ノードを取得し、その後は受信要求を実行せず、関係をたどります。
フォールトの発動は比較的高価なプロセスになるため(場合によっては、永続ストアとの間を往復する必要があります)、不必要なフォールトの発動を避けたいこともあります。以下のメソッドは、フォールトを対象にフォールトを発動させることなく、安全に呼び出すことができます。isEqual:、hash、superclass、class、self、zone、isProxy、isKindOfClass:、isMemberOfClass:、conformsToProtocol:、respondsToSelector:、retain、release、autorelease、retainCount、description、managedObjectContext、entity、objectID、isInserted、isUpdated、isDeleted、および isFault。
isEqual および hash はフォールトを発動しないため、管理対象オブジェクトは一般的にフォールトを発動させずにコレクションに配置することができます。ただし、コレクションオブジェクトを対象にキー値コーディングメソッドを呼び出すと、管理対象オブジェクトを対象に valueForKey: が呼び出されることがあり、結果としてフォールトが発動される場合があります。さらに、description のデフォルト実装ではフォールトは発動しませんが、カスタムの description メソッドを実装してオブジェクトの永続プロパティにアクセスすると、フォールトが発動します(ただし、description はオーバーライドしないことを強くお勧めします)。
2 つのアプリケーションで同じデータストアを使用したり、1 つのアプリケーションに複数の永続性スタックがある場合は、いずれかの管理対象オブジェクトコンテキストまたは永続オブジェクトストアの管理対象オブジェクトが、リポジトリの内容との同期を失う可能性があります。そうなった場合は、管理対象オブジェクト、そして特に永続オブジェクトストア(スナップショット)のデータを「リフレッシュ」して、データ値を最新の状態にする必要があります。
それには、編集コンテキストメソッド -refreshObject: mergeChanges: を使用します。
mergeChanges フラグが YES であれば、オブジェクトと永続ストアコーディネータで利用できるオブジェクトの状態をマージします。このフラグが NO の場合、状態をマージせずに単純にオブジェクトを再フォールトします(その結果、関連する他の管理対象オブジェクトも解放されるので、このメソッドを使用して、メモリに持ちたいオブジェクトグラフを部分的に縮小できます)。
Preliminary Last updated: Tiger
|
Get information on Apple products.
Visit the Apple Store online or at retail locations. 1-800-MY-APPLE Copyright © 2007 Apple Inc. All rights reserved. | Terms of use | Privacy Notice |