2009-05-17 6 views
3

私は別のクラスへのポインタを含むobjective-cクラスを持っています。私はこのクラスのインスタンスをNSCoder経由でアーカイブします:NSCoder - ポインタをアーカイブしますか?

@interface Barn 
{ 
    int m_numHorses; 

    // Barn does not allocate this instance, it just points to it. 
    Farmer* m_pFarmer; 
} 
@end 

... 

- (void)encodeWithCoder:(NSCoder *)encoder 
{ 
    [encoder encodeInt:m_numHorses forKey:@"numHorses"]; 
    [encoder encode?:m_pFarmer forKey:@"pFarmer"]; 
} 

- (void) setPointer:(Farmer*)pFarmer 
{ 
    m_pFarmer = pFarmer; 
} 

どのようにm_pFarmerポインタをアーカイブしますか?それは私にとっては意味がありませんが、それはすべてのアドレスなので、デシリアライズ時に後でリンクを復元する方法を知っているようにNSCoderがディスクにシリアル化できるものは何もわかりません。

答えて

3

encodeObject:を使用し、FarmerクラスにNSCodingを実装する必要があります。そのため、再帰的に呼び出されます。

+0

ああ申し訳ありませんが、私はもっと明確にすべきです - m_pFarmerは単にシステム内の他の場所に割り当てられたFarmerオブジェクトへのポインタです - Barnクラスインスタンスは所有していません - –

+0

このコードの外にFarmerオブジェクトを格納していますか?あなたがそうでないなら、再帰的にそれを保存することは意味があります。 – pgb

6

ポインタを直接エンコードすることはできません。オブジェクトをアーカイブ解除すると、ポインタの値がまったく異なるためです。つまり、それを格納することができます

encodeValueOfObjCType:@encode(id) at:&m_pFarmer 

しかし、逆シリアル化されたポインタがデシリアライズされた農家を指すことは保証されません。実際、そうでない可能性は非常に高いです。

BarnFarmerを所有していない場合は、Barnはデシリアライズ時に再作成しないでください。元のものとは別の新しいFarmerで終了します。必要なのは、元のFarmerの逆シリアル化されたインスタンスを検索し、BarnのFarmerのインスタンスを他のインスタンスに置き換える方法です。

誰かがFarmerを所有していますか?したがって、BarnfindMyFarmerメソッドを持つ必要があり、FarmerOwnerをすべて調べ、使用する元のインスタンスを探します。 (たぶんFarmerfarmerIDのivarを比較することによって)?完了したらBarn-[NSObject awakeAfterUsingCoder:(NSCoder *)]を実装して、農家の交換ルーチンを起動することができます。

希望は意味があります。アーカイブとシリアライゼーションのdocumentationをご覧ください。特に、のオブジェクトをエンコードしてデコードするページを参照すると、オンザフライでオブジェクトを置き換えることができます。

更新

NSArchiver sおよびNSKeyedArchiver sが、オブジェクトがアーカイブ内の他のオブジェクトはすでにそれを追加した場合のみ、アーカイブに追加されている(encodeConditionalObject:経由)、conditional archivingのアイデアをサポートしています。ドキュメントには「」と書かれていますが、通常、条件オブジェクトは弱い、または保持されていないオブジェクトへの参照をエンコードするために使用されます。 "したがって、Farmerが既にアーカイブされている場合は、追加することをお勧めしますが、Barnを農家なしでエンコードしている場合は、そうしたくありません。

上記のドキュメントをぜひご覧ください。

+0

おかげ条件アーカイブを言及するために、エンコード後にそれが正常に復号できたと弱参照 - (ボイド)encodeConditionalObject:(ID)objv forKey:(NSStringの*)キー – Binarian

3

まず、BJが指すドキュメントを読む必要があります。

シリアライゼーションライブラリは、同じオブジェクトのリピートを検出するのに十分スマートで、1回のみエンコードします。したがって、後で必要とする場合は、一般に、このオブジェクトをエンコードする必要があります。シリアライゼーションライブラリは、グラフループを処理することさえできます。あなたはこれらのことを心配する必要はなく、積極的にでなければなりません。他のオブジェクトがこのオブジェクトをどのように処理するかを第二に推測してみてください。ObjCには、C++にしばしば必要とされるオブジェクト所有概念のようなものはありません。カウントされた参照メモリ管理はそれを必要とせず、再作成しないでください。

参考カウントといえば、あなたのセッターにファーマーを残さないことを意味しますか?バーンはすでにファーマーを保持しているからですか?または、このガベージコレクションコードですか?それとも、これは意図的でないままでしたか?これは、あなたが実際にそれを保有していない場合、このものをデシリアライズすると間違いなくクラッシュする可能性があります。

0

ポインタが保持しているアドレスを文字通りエンコードしたい場合は、Farmerオブジェクトがアーカイブをデコードするまでその場所に留まることを保証できるので、ポインタをNSIntegerとしてエンコードできます。

すなわち[encoder encodeInteger:(NSInteger)m_pFarmer forKey:@"pFarmer"];

は、一般的にいえ話すあなたは長いアーカイブよりFarmerオブジェクト上に保持するために非常に慎重でない限り、これは悪い考えです。

0

私は同様のことをしました。あなたのケースでは、私はその後、私はNSCodingを使用して農家にこのUUIDを救う

var uniqueIdentifier: String = NSUUID().UUIDString 

を使用して、農民のためのUUID(一意の識別子)を生成します。

私もこのUUIDを経由して農家への物置ポイントを持っているでしょうが(あなたがUUID経由ファーマーを決定する納屋に計算された「ファーマー」の特性を持つことができます)。 NSCodingでバーンのUUIDを保存します。 この方法では、ディスクにデータを保存するときにポインタを失うことはありません。もちろん

、より良い技術的な解決策はCoreDataを使用することですが、それは別の話だ...

編集:私はNSCodingで別のオブジェクトへのポインタをエンコードしようとした場合を持っていました。私の場合は、株式を指し示す株式アラートでした(株のプロパティとして定義されています)。 NSCodingが現在の状態で「凍結」、元のオブジェクトのコピーを作成したことが表示されます。そのコピーは元のオブジェクトから独立して生きていました。株式は、いくつかの(現在の株価)、他の計算された(通貨のゲインまたは%)が格納されているプロパティを持っています。 (他の要因に依存して)計算された特性が進化しつつ在庫アラートのストックプロパティの保存された性質は、変化しませんでした。 だから、私の経験の結論は、それがNSCodingを持つ別のオブジェクトへのポインタを保存しようとして良いアイデアではないということでしょう。

関連する問題