1

アプリを停止して再起動するまで、アプリは正常に動作します - アーカイブ ファイル - highScores.archive が存在します。次に、アプリがエンコードを中断します。最初の行で EXC_BAD_ACCESS を取得します (長い間、エンコードしている日付オブジェクトに到達するまで発生しませんでした。

私の推測では、いくつかの場所に保持を配置する必要があると思いますが、どこにあるのかわかりません。

コード:

FlipHighScores.h

...

@interface FlipHighScores : NSObject <NSCoding> {
//NSString *themeChosen;
NSInteger newHighScore;
NSInteger newScoreStartLevel;
NSInteger newScoreFinishLevel;
NSDate *scoreDateCreated;}

@property (copy, nonatomic) NSString *themeChosen;
@property (nonatomic) NSInteger highScore;
@property (nonatomic) NSInteger scoreStartLevel;
@property (nonatomic) NSInteger scoreFinishLevel;
@property (nonatomic, readonly, strong) NSDate *scoreDateCreated;

...

FlipHighScores.m ...

@synthesize themeChosen = _themeChosen;
@synthesize highScore = _highScore;
@synthesize scoreStartLevel = _scoreStartLevel;
@synthesize scoreFinishLevel = _scoreFinishLevel;
@synthesize scoreDateCreated = _scoreDateCreated;

...

-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_themeChosen forKey:@"_themeChosen"];
NSLog(@"Theme Chosen is %@", _themeChosen);
[aCoder encodeInt:_highScore forKey:@"_highScore"];
[aCoder encodeInt:_scoreStartLevel forKey:@"_scoreStartLevel"];
[aCoder encodeInt:_scoreFinishLevel forKey:@"_scoreFinishLevel"];
NSLog(@"Date Created in encodeWithCoder is %@", _scoreDateCreated);
[aCoder encodeObject:_scoreDateCreated forKey:@"_scoreDateCreated"];}

-(id)initWithCoder:(NSCoder *)aDecoder {
if (self) {
    _themeChosen = [aDecoder decodeObjectForKey:@"_themeChosen"];
    _highScore = [aDecoder decodeIntForKey:@"_highScore"];
    _scoreStartLevel = [aDecoder decodeIntForKey:@"_scoreStartLevel"];
    _scoreFinishLevel = [aDecoder decodeIntForKey:@"_scoreFinishLevel"];
    _scoreDateCreated = [aDecoder decodeObjectForKey:@"_scoreDateCreated"];
}
return self;}

-(NSString *)description {
NSDate *date = _scoreDateCreated;
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
NSString *dateString = [dateFormatter stringFromDate:date];
//NSLog(@"dateString from description is %@", dateString);
NSString *descriptionString = [[NSString alloc] initWithFormat:@"%d %@ S:%d F:%d D:%@", _highScore, _themeChosen, _scoreStartLevel, _scoreFinishLevel, dateString];
return descriptionString:}

ややこしいのは、保存ファイル (highScores.archive) を削除してアプリを実行すると、問題なく実行されることです。アプリを停止して強制終了し、再度起動します。最初にエンコーディングが呼び出されたときにクラッシュします。

themeChosen オブジェクトをエンコードする行。「保持」またはに変更することで修正されるデコードの問題に関するいくつかの投稿を読みました。フォーマット(なぜそれが役立つのか、私にはよくわかりません)。しかし、これはエンコーディングです。デコードはおそらく次の質問になるでしょう...

このプロジェクトでは ARC を使用していません。たぶん、すべてを最初から再構築すると...

ああ、Theme 変数の追跡を追加するまでテストした限り、すべてがスムーズに実行されていたことを忘れていました。その後、ここで述べたように、事態は少しうまくいきませんでした。

4

1 に答える 1

4

あなたの問題はあなたにあると思います-initWithCoder。結果を取得し-decodeObjectForKey:て、合成されたivarに直接割り当てています。名前に「コピー」という単語が含まれていないメソッドは、通常、自動解放されたオブジェクトを返すと見なされます。

自動解放されたオブジェクトを変数に直接割り当てると、そのオブジェクトは次の実行ループで解放され、それ自体の割り当てが解除され、変数がジャンク メモリを指すようになります。アクセスしようとすると、exec_bad_access.

あなたがしなければなら@synthesizeないことは、あなたのために作成するアクセサメソッドを利用することです. それ以外の

_themeChosen = [aDecoder decodeObjectForKey:@"_themeChosen"];

あなたは書くべきです

[self setThemeChosen:[aDecoder decodeObjectForKey:@"_themeChosen"]];

または、等号を積極的に使用する必要がある場合は、「ドット表記」の構文シュガーを使用できます。

self.themeChosen = [aDecoder decodeObjectForKey:@"_themeChosen"]

これは、最終的にはほぼ同じものに変換されます。

重要なのは、合成されたセッターは単にオブジェクトを ivar に割り当てるだけではありません。また、オブジェクトも保持します (実際、この場合、宣言で指定したため、オブジェクトをコピーします)。これは、ivar に直接アクセスしてはならず、常にアクセサーを使用してはならない、非常に多くの、多くの理由の 1 つにすぎません。copy@property@property@synthesize

更新:宣言にあると宣言したため、表示に問題
があることがわかります。なぜ読み取り専用なのですか?派生値ではないように見えるため、明らかに何かを割り当てる必要があります。scoreDateCreatedreadonly@property

オブジェクトで読み取り/書き込みが必要で、読み取り専用インターフェイスのみを公開したい場合は@property、 の上部にある匿名カテゴリで を読み取り/書き込みとして再宣言できますFlipHighScores.m。したがって、ヘッダーを含むものはすべて読み取り専用に見えますが、実際にはオブジェクトの実装内で読み取り/書き込みです。

于 2012-05-02T03:32:35.077 に答える