我正也想写一篇关于iphone数据存储的文章。关于存储,分为持久性的数据存储和运行时的数据存储,前者在app关闭之后数据仍然存在,而后者是在程序运行时才存在。再具体一点,则前者关闭之后仍然数据存在说明数据以特定的形式存储在设备上。 后者在运行时存在,说明是在内存中,全局或者局部的变量,在app关闭之后内存回收,数据也就销毁了。所以,可以看出,一个持久性的数据存储就必须的要以某种形式写在设备上,iphone中通常采用的就是文件。看到了himi写的一篇有关持久化数据存储的文章,大体已经包含了持久化存储的常用策略,分享给大家,也免去了我码字之苦啊,善哉。其中需要说明的一点是,在ios应用开发中的常用数据库存储是coredata,相较于sqlite,其具有更好的封装和便捷的使用。
OK,今天Himi介绍游戏存储这一块,在Android游戏开发中Himi介绍了好几种保存的方式和形式,那么在iOS中也有几种方式,一般常用的有以下四种形式:
1. NSKeyedArchiver(加密形式)
2. NSUserDefaults
3. Write写入方式
4. SQLite3
这里Himi就不再介绍SQlite数据库了,Android游戏存储中我也介绍过SQLite如何保存数据,但是由于这一块很多童鞋没有接触过数据库相关知识,所以即使讲了也没作用,那么对于数据数据库的童鞋们可以参考其他博文或书籍进行学习;
首先介绍第一种保存方式:NSKeyedArchiver
代码很简单就不多解释了直接上代码:
- //=================NSKeyedArchiver========================
- NSString *saveStr1 = @"我是";
- NSString *saveStr2 = @"数据";
- NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
- //----Save
- //这一句是将路径和文件名合成文件完整路径
- NSString *Path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
- NSString *filename = [Path stringByAppendingPathComponent:@"saveDatatest"];
- [NSKeyedArchiver archiveRootObject:array toFile:filename];
- //用于测试是否已经保存了数据
- saveStr1 = @"hhhhhhiiii";
- saveStr2 =@"mmmmmmiiii";
- //----Load
- array = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];
- saveStr1 = [array objectAtIndex:0];
- saveStr2 = [array objectAtIndex:1];
- CCLOG(@"str:%@",saveStr1);
- CCLOG(@"astr:%@",saveStr2);
首先介绍第二种保存方式:NSUserDefaults
代码很简单就不多解释了直接上代码:
- //=================NSUserDefaults========================
- NSString *saveStr1 = @"我是";
- NSString *saveStr2 = @"数据";
- NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
- //Save
- NSUserDefaults *saveDefaults = [NSUserDefaults standardUserDefaults];
- [saveDefaults setObject:array forKey:@"SaveKey"];
- //用于测试是否已经保存了数据
- saveStr1 = @"hhhhhhiiii";
- saveStr2 =@"mmmmmmiiii";
- //---Load
- array = [saveDefaults objectForKey:@"SaveKey"];
- saveStr1 = [array objectAtIndex:0];
- saveStr2 = [array objectAtIndex:1];
- CCLOG(@"str:%@",saveStr1);
- CCLOG(@"astr:%@",saveStr2);
首先介绍第三种保存方式:Write写入方式
代码很简单就不多解释了直接上代码:
- //=================Write写入方式========================
- NSString *saveStr1 = @"我是";
- NSString *saveStr2 = @"数据";
- NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
- //----Save
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- if (!documentsDirectory) {
- NSLog(@"没找到");
- }
- NSMutableArray *saveDataArray=nil;
- NSString *appFile = [documentsDirectory stringByAppendingPathComponent:@"Savedatas.plist"];
- [[NSArray arrayWithObjects:array,nil] writeToFile:appFile atomically:NO];
- //用于测试是否已经保存了数据
- saveStr1 = @"hhhhhhiiii";
- saveStr2 =@"mmmmmmiiii";
- //----Load
- if([[NSFileManager defaultManager] fileExistsAtPath:appFile]){
- saveDataArray = [NSMutableArray arrayWithContentsOfFile:appFile];
- } else{
- saveDataArray = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Savedatas" ofType:@"plist"]];
- }
- NSArray *strArray = [saveDataArray objectAtIndex:0];
- saveStr1 = [strArray objectAtIndex:0];
- saveStr2 = [strArray objectAtIndex:1];
- CCLOG(@"str:%@",saveStr1);
- CCLOG(@"astr:%@",saveStr2);
不论哪种形式代码都很容易理解,那么以上三种保存方式代码中都带有如下两行代码;
- saveStr1 = @"hhhhhhiiii";
- saveStr2 =@"mmmmmmiiii";
我已经注释上了,为了验证是否保存数据成功,如果没有保存成功,最后打印的肯定就是hhhhhhiiiiiiiii,mmmmiiiii啦~正常保存的话如下图控制台信息:
由于本章介绍过于简单,那么下面Himi对Write写入方式保存数据和读取数据封装了两个方法这里放出,给童鞋们行个方便:(其他两种大家封装起来风容易了,这里就不写了);
封装的函数如下:
- //保存游戏数据
- //参数介绍:
- // (NSMutableArray *)data :保存的数据
- // (NSString *)fileName :存储的文件名
- -(BOOL) saveGameData:(NSMutableArray *)data saveFileName:(NSString *)fileName
- {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- if (!documentsDirectory) {
- NSLog(@"Documents directory not found!");
- return NO;
- }
- NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
- return ([data writeToFile:appFile atomically:YES]);
- }
- //读取游戏数据
- //参数介绍:
- // (NSString *)fileName :需要读取数据的文件名
- -(id) loadGameData:(NSString *)fileName
- {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
- NSMutableArray *myData = [[[NSMutableArray alloc] initWithContentsOfFile:appFile] autorelease];
- return myData;
- }
使用代码如下:
- NSString *saveStr1 = @"测试保存读取";
- NSString *saveStr2 = @"两个函数";
- NSMutableArray *array = [NSMutableArray arrayWithObjects:saveStr1, saveStr2, nil];
- [self saveGameData:array saveFileName:@"Himi"];
- NSMutableArray*temp =(NSMutableArray*)[self loadGameData:@"Himi"];
- CCLOG(@"%@--%@",[temp objectAtIndex:0],[temp objectAtIndex:1]);
运行效果截图如下:
这里Himi要提醒大家两点细节也是需要注意的地方:
1.对于取出数据的时候需要注意,例如如下代码:
- NSUserDefaults *saveDefaults = [NSUserDefaults standardUserDefaults];
- NSMutableArray *arraySaveData =[saveDefaults objectForKey:@"OhSaveData"];
- //NSMutableArray *arraySaveData=[NSMutableArray arrayWithArray:[saveDefaults objectForKey:@"OhSaveData"]];
第二句代码是通过一个文件名获取你存储的数据,返回数据数组,但是!一定要注意这里返回的数据数组是不可修改的!及时你将读取的数据赋给一个可修改的数组中也一样无法修改其中的数据,所以如果你想将取出的数据进行修改那么这里需要要使用第三行代码来获取,这里Himi将获取出的数据数组首先copy给了可修改数组中,那么此时你的可修改数组就可以正常修改了!
2.修改已经的存储文件;代码如下:
- NSUserDefaults *saveDefaults = [NSUserDefaults standardUserDefaults];
- [saveDefaults setObject:arraySaveData forKey:@"已经存在的文件名"];
arraySaveData:表示新的数据数组