2

基本的に、NSMutableDictionary から派生した OrderedDictionary と呼ばれるオープン ソース コードを使用しています。次に、OrderedDictionary クラスにエンコードおよびデコード メソッドを追加して、順序付けされた辞書データを NSUserDefaults に保存します。ただし、encode および decode メソッドが呼び出されていないことに気付きました。その結果、デコードされた辞書は順序付けられなくなりました。以下は私のコードです:

@interface OrderedDictionary : NSMutableDictionary <NSCopying, NSCoding>
{
    NSMutableDictionary *dictionary;
    NSMutableArray *array;
}

実装ファイル内:

/**
 * encode the object
 **/
- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
    [coder encodeObject:dictionary forKey:@"dictionary"];
    [coder encodeObject:array forKey:@"array"];
}

/**
 * decode the object
 */
- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self != nil)
    {
        dictionary = [coder decodeObjectForKey:@"dictionary"];
        array = [coder decodeObjectForKey:@"array"];
    }   
    return self;
}

これを使用するための簡単なコード例:

dictionary = [[OrderedDictionary alloc] init];
[dictionary setObject:@"one" forKey:@"two"];
[dictionary setObject:@"what" forKey:@"what"];
[dictionary setObject:@"7" forKey:@"7"];
NSLog(@"Final contents of the dictionary: %@", dictionary);

if ([[NSUserDefaults standardUserDefaults] objectForKey:@"myDictionary"] == nil)
{
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:dictionary] 
                                          forKey:@"myDictionary"];
}
else
{
    NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];

    NSData *savedDictionary = [currentDefaults objectForKey:@"myDictionary"];

    if (savedDictionary != nil)
    {
        OrderedDictionary *oldData = [NSKeyedUnarchiver unarchiveObjectWithData:savedDictionary];
        if (oldData != nil) 
        {
            NSLog(@"Final contents of the retrieved: %@", oldData);

        } 
    }
}

問題は、最終的な retrieveDictionary には元のデータ順序がなく、エンコードおよびデコード メソッドがまったく呼び出されないことです。

事前に助けてくれてありがとう!:)

4

2 に答える 2

4

-classForCoderOrderedDictionary でオーバーライドする必要がある NSObject メソッドが呼び出されます。ドキュメントから:

classForCoder
サブクラスによってオーバーライドされ、コーディング中にそれ自身以外のクラスに置き換えられます。

-(Class)classForCoder
戻り値
コーディング時に受信者自身のクラスを置き換えるクラス。

考察
このメソッドは NSCoder によって呼び出されます。NSObject の実装は、レシーバーのクラスを返します。クラス クラスタのプライベート サブクラスは、アーカイブ時にパブリック スーパークラスの名前に置き換えられます。

その最後の行が鍵です。したがって、OrderedDictionary.m では次のようになります。

- (Class)classForCoder 
{  
    return [self class]; // Instead of NSMutableDictionary
} 

また、ARC を使用していない場合は、 から返されたオブジェクトを必ず保持してください-decodeObjectForKey。rob mayoff が以下で述べているように、[super initWithCoder:] (または[super encodeWithCoder:') を呼び出すべきではありません。衝突を避けるためにキー文字列も変更しました。

- (id)initWithCoder:(NSCoder *)coder
{
    if (self != nil)
    {
        dictionary = [[coder decodeObjectForKey:@"OrderedDictionary_dictionary"] retain];
        array = [[coder decodeObjectForKey:@"OrderedDictionary_array"] retain];
    }   
    return self;
}
于 2012-04-09T18:04:34.290 に答える
0

OrderedDictionary間違った初期化子で新しいを作成している可能性がありますinitWithDictionary:. 代わりにこれを試してください:

OrderedDictionary *oldData = [NSKeyedUnarchiver unarchiveObjectWithData: savedDictionary];
if (oldData != nil) 
{
    NSLog(@"Final contents of the retrieved: %@", oldData);
}

引数として必ずinitWithDictionary:期待してください。OrderedDictionary私の推測では、NSDictionary.

編集: デフォルトを保存するコードには、次のようなものが含まれている必要があります。

OrderedDictionary *myDict = ...;
NSData* data = [NSKeyedArchiver archivedDataWithRootObject: myDict];
[[NSUserDefaults standardDefaults] setObject: data forKey: @"myDictionary"];
于 2012-04-04T04:53:05.987 に答える