I am making an iOS game and need to save the highest level the player has reached. I can successfully change a data element in a plist, but for some reason, that data keeps reverting to its original value every time the game restarts. Here is the basic flow of my code:
我正在制作一个iOS游戏,需要保存玩家已经达到的最高水平。我可以成功地更改plist中的数据元素,但由于某些原因,每次游戏重新启动时,数据都会恢复到原来的值。下面是我的代码的基本流程:
In the game's init, get the highest level the player has reached (the original value is 1)
在游戏的init中,获取玩家已经达到的*别(初始值为1)
pData = [[PlayerData alloc] init];
currentLevel = [[pData.data valueForKey:@"Highest Level"] intValue];
[self startNewLevel:currentLevel];
'data' is an NSMutableDictionary that gets initialized like this in PlayerData:
“data”是一个NSMutableDictionary,它在PlayerData中像这样初始化:
self.data = [NSMutableDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"playerdata" ofType:@"plist"]];
later, if the player beats the highest level, I increment the 'highest level' value and write to the file by calling this function in PlayerData:
之后,如果玩家打败了*别,我增加“*别”的值,并通过调用PlayerData中的这个函数写入文件:
-(void) newHighestLevel:(NSString*)path :(int)level{
[self.data setValue:[NSNumber numberWithInt:level] forKey:path];
[self.data writeToFile:@"playerdata.plist" atomically:YES]
I know all this is working because I have a level menu that the player can access while playing the game. Each time the player presses the level menu button, a subclass of a UITableView gets created that displays level 1 through the highest level reached. The initialization looks like this:
我知道这一切都在起作用,因为我有一个水平菜单,玩家可以在玩游戏时访问它。每当玩家按下一级菜单按钮时,就会创建一个UITableView的子类,该子类会通过到达的*别显示1级。初始化是这样的:
levelMenu = [[LevelMenu alloc] init:[[pData.data valueForKey:@"Highest Level"] intValue]];
The level menu displays the correct number of levels while in the game (e.g. if the player hasn't beat any levels and goes to the level menu, it just displays "level 1"; but if the player beats level 1 and goes to the level menu, it displays "level 1" and "level 2"). However, whenever the app gets terminated or the user quits to the games main menu, the value for 'highest level' reverts back to 1 and this code:
在游戏中,关卡菜单显示正确的关卡数(例如,如果玩家没有超过任何关卡并进入关卡菜单,它只显示“关卡1”;但是如果玩家打败了一级并进入一级菜单,它会显示“一级”和“二级”)。但是,当应用程序终止或用户退出游戏主菜单时,“*别”的值恢复为1,代码如下:
currentLevel = [[pData.data valueForKey:@"Highest Level"] intValue];
always sets currentLevel to 1 when the player pushes start, no matter how many levels the user beat while playing.
当玩家启动时,总是将currentLevel设置为1,不管玩家在玩的时候打了多少关卡。
Why is the value changing back? Am I missing something that would make my plist edits permanent?
为什么值会回调?我是否遗漏了一些可以让我的plist编辑永久编辑的东西?
EDIT:
编辑:
here is my new 'newHighestLevel' method:
下面是我的新方法“newHighestLevel”:
-(void) newHighestLevel:(NSString*)path :(int)level{
[self.data setValue:[NSNumber numberWithInt:level] forKey:path];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *docfilePath = [basePath stringByAppendingPathComponent:@"playerdata.plist"];
[self.data writeToFile:docfilePath atomically:YES];
self.data = [NSMutableDictionary dictionaryWithContentsOfFile:docfilePath];
BOOL write = [self.data writeToFile:docfilePath atomically:YES];
}
write gets set to YES. If I change 'docfilePath' to @"playerdata.plist", it gets set to NO. Nothing seems to change with the game in either case.
写入被设置为YES。如果我将“docfilePath”更改为“@”playerdata。plist,它被设置为NO。在这两种情况下,游戏似乎都没有改变。
SOLUTION:
解决方案:
-(void) newHighestLevel:(NSString*)path :(int)level{
[self.data setValue:[NSNumber numberWithInt:level] forKey:path];
NSString *basePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *docfilePath = [basePath stringByAppendingPathComponent:@"playerdata.plist"];
[self.data writeToFile:docfilePath atomically:YES];
}
and in init
在初始化
-(id) init{
NSString *basePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *docfilePath = [basePath stringByAppendingPathComponent:@"playerdata.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:docfilePath]){
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"playerdata" ofType:@"plist"];
[fileManager copyItemAtPath:sourcePath toPath:docfilePath error:nil];
}
self.data = [NSMutableDictionary dictionaryWithContentsOfFile:docfilePath];
return self;
}
2 个解决方案
#1
11
The easiest way to create a dictionary from a plist is to use the method dictionaryWithContentsOfFile:,
从plist中创建字典最简单的方法是使用method dictionaryWithContentsOfFile:,
For example, to load a plist from your resources:
例如,要从您的资源中加载一个plist:
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"playerData" ofType:@"plist"];
NSMutableDictionary *plistdict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
Writing a plistdict is equally simple:
写一份清单同样简单:
[plistdict writeToFile:filePath atomically:YES];
Note that you can't write into your app's resources, so you'll have to create a different path, e.g. in your Documents directory for your plist.
请注意,您不能将其写入应用程序的资源中,因此必须创建一个不同的路径,例如在plist的Documents目录中。
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *docfilePath = [basePath stringByAppendingPathComponent:@"playerData.plist"];
[plistdict writeToFile:docfilePath atomically:YES];
Now retrieve data from plist again.
现在再次从plist中检索数据。
NSMutableDictionary *plistdict = [NSMutableDictionary dictionaryWithContentsOfFile:docfilePath];
Add your content in plistDict and write it again.
把你的内容添加到plistDict,再写一次。
#2
2
the method writeToFile:atomically
returns a BOOL
result. I guess the file is not being saved at all.
方法writeToFile:以原子方式返回BOOL结果。我猜文件根本没有保存。
The reason why your game works correctly is because the application reads the data from Dictionary
(which is populated on launch once), not directly from plist
file every time (and it shouldn't either).
游戏正常运行的原因是应用程序从Dictionary(在启动时填充一次)读取数据,而不是每次都直接从plist文件读取数据(也不应该如此)。
Check to see the return value of writeToFile:atomically
method to determine whether file is actually being saved or not.
检查writeToFile:原子方法的返回值,以确定文件是否被实际保存。
#1
11
The easiest way to create a dictionary from a plist is to use the method dictionaryWithContentsOfFile:,
从plist中创建字典最简单的方法是使用method dictionaryWithContentsOfFile:,
For example, to load a plist from your resources:
例如,要从您的资源中加载一个plist:
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"playerData" ofType:@"plist"];
NSMutableDictionary *plistdict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
Writing a plistdict is equally simple:
写一份清单同样简单:
[plistdict writeToFile:filePath atomically:YES];
Note that you can't write into your app's resources, so you'll have to create a different path, e.g. in your Documents directory for your plist.
请注意,您不能将其写入应用程序的资源中,因此必须创建一个不同的路径,例如在plist的Documents目录中。
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *docfilePath = [basePath stringByAppendingPathComponent:@"playerData.plist"];
[plistdict writeToFile:docfilePath atomically:YES];
Now retrieve data from plist again.
现在再次从plist中检索数据。
NSMutableDictionary *plistdict = [NSMutableDictionary dictionaryWithContentsOfFile:docfilePath];
Add your content in plistDict and write it again.
把你的内容添加到plistDict,再写一次。
#2
2
the method writeToFile:atomically
returns a BOOL
result. I guess the file is not being saved at all.
方法writeToFile:以原子方式返回BOOL结果。我猜文件根本没有保存。
The reason why your game works correctly is because the application reads the data from Dictionary
(which is populated on launch once), not directly from plist
file every time (and it shouldn't either).
游戏正常运行的原因是应用程序从Dictionary(在启动时填充一次)读取数据,而不是每次都直接从plist文件读取数据(也不应该如此)。
Check to see the return value of writeToFile:atomically
method to determine whether file is actually being saved or not.
检查writeToFile:原子方法的返回值,以确定文件是否被实际保存。