我正在制作一个简单的应用来追踪我女儿的曲棍球比赛。我的问题是,当我停止并重新启动应用程序时,一些数据不会被重新加载。(我正在检查一个日志语句,只显示零,无论之前有什么。)我不确定是否问题在于加载或保存。
(对不起,很长的帖子,但我不确定在哪里看。)
它使用如下所示的Games类:
#import <Foundation/Foundation.h>
@interface Game : NSObject <NSCoding>//conforms to this protocol so data can be prepared for read/write to file
//used primarily in GameFactsViewController
@property (nonatomic, strong) NSString *opponent;
@property (nonatomic, strong) NSDate *dateOfGame;
//used primarily in PlayerActionsViewController
@property (nonatomic) NSInteger shotsOnGoal;
@property (nonatomic) NSInteger shotsNotOnGoal;
@property (nonatomic) NSInteger passesCompleted;
@property (nonatomic) NSInteger passesNotCompleted;
@property (nonatomic) NSInteger takeaways;
@property (nonatomic) NSInteger giveaways;
@property (nonatomic) NSInteger faceoffsWon;
@property (nonatomic) NSInteger faceoffsLost;
@property (nonatomic) NSInteger shifts;
@property (nonatomic) NSInteger blockedShots;
@end
我的问题是对手和dateOfGame属性,并在我再次启动应用程序时得到保存和加载,但没有其他属性。
Tha主控制器是一个tableview控制器,每个游戏作为一行。对手和dateOfGame属性设置在tableview控制器中,其他属性设置在选项卡栏控制器内的视图控制器中。这些控制器的序列来自第一个的披露指示器,并通过点击第二个行。这些工作正常,使用此代码:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//check for proper seque
if ([segue.identifier isEqualToString:@"AddGame"]) {
//identify the top level view controller holding the GameFactsVC (see storyboard)
UINavigationController *navigationController = segue.destinationViewController;
//go down one level to get the GFVC
GameFactsViewController *controller = (GameFactsViewController *) navigationController.topViewController;
//set the current controller (the HSVC) as the delegate for the GFVC
controller.delegate = self;
} else if ([segue.identifier isEqualToString:@"EditGame"]) {
//as above to get to the right place
UINavigationController *navigationController = segue.destinationViewController;
GameFactsViewController *controller = (GameFactsViewController *) navigationController.topViewController;
controller.delegate = self;
//"sender" here is what was clicked, the detail disclosure icon
//this identifies what game data to load to edit
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
controller.gameToEdit = _games[indexPath.row];
} else if ([segue.identifier isEqualToString:@"GameDetails"]) {
UITabBarController *tabBarController = segue.destinationViewController;
PlayerActionsViewController *controller = (PlayerActionsViewController *)[[tabBarController viewControllers] objectAtIndex:0];
controller.delegate = self;
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
controller.gameToEditPerformance = _games[indexPath.row];
NSLog(@"Data passed %ld", (long)controller.gameToEditPerformance.shotsOnGoal);
}
}
我使用此方法为对手和dateOfGame返回主控制器,我可以记录回来的数据。
-(IBAction) done
{
//Use delegate to capture entered data and pass to HSVC
//methods here are delegate methods listed above and defined in the HSVC
//see if the data was empty when view loaded
if (self.gameToEdit == nil) {
Game *game = [[Game alloc] init];
game.opponent = self.opponentField.text;
game.dateOfGame = [self convertToDate:self.dateLabel.text withFormat:@"MMM d, yyyy"];
[self.delegate gameFactsViewController:self didFinishAddingGame:game];
} else {
self.gameToEdit.opponent = self.opponentField.text;//updates data model; will update display in delegate method
self.gameToEdit.dateOfGame = [self convertToDate:self.dateLabel.text withFormat:@"MMM d, yyyy"];
[self.delegate gameFactsViewController: self didFinishEditingGame:self.gameToEdit];
}
}
同样地,我在另一个控制器中使用此行传递剩余的数据,该方法在设置数据值的long方法结束时也可以记录回来的正确数据。
[self.delegate playerActionsViewController:self didEditGameData:self.gameToEditPerformance];
我用这两种类似的方法调用Save方法。 (我看到的关键区别是因为我已经更新了另一个表中的显示,而我仍然需要更新主视图。)
- (void) gameFactsViewController:(GameFactsViewController *)controller didFinishEditingGame:(Game *)game
{
//edit already made in data model in GFVC
//need to update display
NSInteger index = [_games indexOfObject: game];//locate the item being edited in the games array
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];//get the right cell
[self configureDataForCell:cell withGame:game];//puts the game data into the labels in the cell
[self saveGames];//write the current data to the file
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) playerActionsViewController: (PlayerActionsViewController *) controller didEditGameData: (Game *) game
{
NSLog(@"Paased back shots %ld", (long) game.shotsOnGoal);
[self saveGames];
}
现在进行数据保存和加载。我正在使用此代码:
- (void) loadGames
{
NSString *path = [self dataFilePath];//for convenience below
//if there is already a data file, unarchive/decode and load games array
//else create an empty arry to hold games
if ([[NSFileManager defaultManager] fileExistsAtPath: path]) {
NSData *data = [[NSData alloc] initWithContentsOfFile: path];//data structure created and loaded with file data
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: data];//archiver created and connected to data
_games = [unarchiver decodeObjectForKey:@"Games"];
[unarchiver finishDecoding];//data now in games array
} else {
_games = [[NSMutableArray alloc] initWithCapacity:50];
}
}
- (void) saveGames
{
NSMutableData *data = [[NSMutableData alloc] init];//data structure to hold the data to be saved after encoding
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:_games forKey:@"Games"];//I believe key here needs to match class name that will be saved. It tells archiver how to encode object properly
[archiver finishEncoding];//finish encoding, with data now in data structure
[data writeToFile:[self dataFilePath] atomically:YES];//write data structure to file determined above
}
在这里的某个地方,我认为,两种情况之间的_games数组存在差异,但我没有看到它。或者是其他一些问题。
感谢。
答案 0 :(得分:1)
问题出在我的游戏课上。我忘了使用
包含对NSIntegers进行编码和解码的密钥[aCoder encodeInteger:self.shotsOnGoal forKey:@"ShotsOnGoal"];
self.shotsOnGoal = [aDecoder decodeIntegerForKey:@"ShotsOnGoal"];
等