0

アプリの起動間でプロパティの状態を保持するために、 NSKeyedArchiver/を使用してクラスのプロパティのデータをファイルに保存しようとしています。NSKeyedUnarchiver

I have the property declared in MyClass.h like so:

@property (nonatomic, weak) NSDictionary *myDictionary;

and I've created custom getter and setter methods in MyClass.m to make sure the NSDictionary is written to disk:

-(NSDictionary *)myDictionary {
    NSDictionary *dictionary;

    NSString *path = [self pathToDataStore];
    if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
        dictionary = [NSDictionary dictionary];
    } else {
        NSData *archivedData = [NSData dataWithContentsOfFile:path];
        dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
    }

    return dictionary;
}

-(void)setMyDictionary:(NSDictionary *)dictionary {
    NSString *path = [self pathToDataStore];
    NSDictionary *rootObject = [NSDictionary dictionaryWithDictionary:dictionary];
    [NSKeyedArchiver archiveRootObject:rootObject toFile:path];
    self.myDictionary = dictionary;
}

This is causing an infinite loop of calls to [self setMyDictionary], so clearly I'm doing something wrong. But what is the problem?

4

2 に答える 2

3

それ以外の:

self.myDictionary = dictionary;

やったほうがいい:

@synthesize myDictionary;
...

-(void)setMyDictionary:(NSDictionary *)dictionary {

...
myDictionary = dictionary
}

問題が発生すると、次の呼び出しが発生します。

self.myDictionary = dictionary; 

に等しい

[self setMyDictionary:dictionary];
于 2013-09-15T12:17:22.983 に答える
1

デブリからの回答は、セッターで構文を使用すると無限再帰が発生する理由を説明しself.myDictionary(「ドット」構文は単純にセッターを再度呼び出すため)、代わりにアクセサー メソッドでインスタンス変数を使用する必要があることを指摘しています。

そうは言っても、追加の観察がいくつかあります。

  1. 既存のコードを引き締めることができます。たとえば、セッターがアーカイブ用の新しい辞書を作成するのはなぜですか? セッターに渡された をアーカイブするだけで済みますdictionary(何らかの理由でアーカイブが失敗した場合はメッセージをログに記録します)。

    -(void)setMyDictionary:(NSDictionary *)dictionary {
        if (![NSKeyedArchiver archiveRootObject:dictionary toFile:[self pathToDataStore]])
            NSLog(@"%s: archiveRootObject failed", __FUNCTION__);
        _myDictionary = dictionary;
    }
    
  2. ゲッターを参照するたびにself.myDictionary、既に取得されていたとしても、アーカイブから再取得されます。これは非効率的であり、意図しない結果 (if (self.myDictionary == self.myDictionary)... 失敗など) が発生する可能性があります。ディクショナリがない場合にのみ、アーカイブからディクショナリを取得するようにゲッターを定義することができます。

    - (NSDictionary *)myDictionary {
        if (!_myDictionary) {
            NSString *path = [self pathToDataStore];
            if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
                _myDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
            }
        }
    
        return _myDictionary;
    }
    
  3. 両方のアクセサー メソッドを定義したため@synthesize、典型的なアンダースコア規則に従う ivar を明示的に定義する行が必要になる場合があります。

    @synthesize myDictionary = _myDictionary;
    
  4. また、weakメモリ修飾子の使用法も興味深いものです (このクラスではなく、誰がこのオブジェクトを所有しているのでしょうか?)。私はそれを作ることをお勧めしますstrong

于 2013-09-15T17:42:14.773 に答える