以前我们也用到过读取数据,但是没有一个应用程序是将其数据永久性存储,也就是在应用重启,机器重启后数据不会丢失,和上一次最后的数据一致。这章一共定义了三种保持数据的方法,第一种:实用属性列表,第二种:对象归档,第三种:使用Iphone的嵌入式数据库(SQLite3)
给予Iphone应用程序沙盒原理,我们保持的数据都是保存在相对应的应用程序的Document文件夹。既然我们把数据放在每一个应用的Document文件夹中,呢我我们怎么得到相应的路径呢,其实也不是很难。下面是检索文档目录路径的代码:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserdomainMask,YES);
NSString *documentDirectory = [paths objectAtIndex:0];常量NSDocumentDirectory表面我们正在查找的Document目录路径,常量NSUserDomainmask表明我们希望将搜索限制于我们应用程序的沙盒中。这样我们就可以得到该数组的第一值,也仅此一值,因为每一个应用程序只有一个Document文件夹。我们得到了Document的路径,然后和文件名相连接不就是一个完整的路径了吗,这用到了stringByAppendingPathComponent方法:
NSString *filepath = [documentDirectory stringbyAppendingPathComponent:@"filename.xxx"];其中filename.xxx为要命名的文件。
在每一个应用程序中还对应一个temp文件夹,我们怎么获取这个文件夹的路径呢,也比较简单:
NSString *tempPath = NSTemporaryDirectory();
NSString *filePath = [tempPath stringByAppendingPathComponent:@"filename.xxx"];
下面我们来创建该项目:
第一个实用属性列表文件,打开Xcode,创建新项目,选择View-Based Application即可,我创建项目名称是IP_11persistence。打开IP_11persistenceViewController.h,首先定义一个常量用来串联Document。
#define kFileName @"data.plist"
然后定义四个输出口,用来输入和显示数据。
IBOutlet UITextField *show1; IBOutlet UITextField *show2; IBOutlet UITextField *show3; IBOutlet UITextField *show4;
定义两个方法:
-(NSString *)dataFilePath;//用来返回数据文件的完整路径名 -(void)applicationWillTerminate:(NSNotification *)notification;//应用程序在退出时调用,将数据保存到数据列表
然后打开IP_11persistenceViewController.m
添加下面这三个方法:
-(NSString *)dataFilePath//用来返回数据文件的完整路径名 { NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString *paths = [path objectAtIndex:0]; return [paths stringByAppendingPathComponent:kFileName];
}
-(void)applicationWillTerminate:(NSNotification *)notification//应用程序在退出时调用,将数据保存到数据列表 { NSMutableArray *array = [[NSMutableArray alloc]init]; [array addObject:show1.text]; [array addObject:show2.text]; [array addObject:show3.text]; [array addObject:show4.text]; [array writeToFile:[self dataFilePath] atomically:YES]; [array release]; }
-(void)viewDidLoad { NSString *filePath = [self dataFilePath];//得到文件路径 if([[NSFileManager defaultManager] fileExistsAtPath:filePath])//如果该文件存在就加载 { NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath]; show1.text = [array objectAtIndex:0]; show2.text = [array objectAtIndex:1]; show3.text = [array objectAtIndex:2]; show4.text = [array objectAtIndex:3]; [array release]; }

UIApplication *app = [UIApplication sharedApplication]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app]; [super viewDidLoad]; }
代码已经搞定,下面点开Resources文件夹,打开IP_11persistenceViewController.xib,向里面拖入4个UITextField控件,勾掉每一个控件上的Clear When Editing Begin,这样就不是每次选中文本框的时候会自动消失里面的内容了。关联四个控件即可。(在实际的例子当中我添加两个方法,一个是在点击回车时,软键盘自动消失,一个是在点击背景是软键盘自动消失,这两个方法在第四章中有详细的讲解,可以去参考)。build and go运行,这是你输入内容,关闭应用程序,然后在打开,你会发现你刚才输入的内容仍然存在,下面开始第二种方法,使用对象归档的方法。
创建一个新的项目,我的项目名是:IP_11persistence2。创建好以后,在Classes文件夹上点右键创建一个新的类,选择NSObject subclass模板。名称为fourlines。打开fourlines.h,向里面添加四个常量和四个输出口:
#define kField1Key @"show1" #define kField2Key @"show2" #define kField3Key @"show3" #define kField4Key @"show4"
NSString *show1; NSString *show2; NSString *show3; NSString *show4;
打开fourlines.m文件,修改代码:
-(void)encodeWithCoder:(NSCoder *)encoder //对所有的属性进行编码 { [encoder encodeObject:show1 forKey:kField1Key]; [encoder encodeObject:show2 forKey:kField2Key]; [encoder encodeObject:show3 forKey:kField3Key]; [encoder encodeObject:show4 forKey:kField4Key]; }
-(id)initWithCoder:(NSCoder *)decoder//使用相同的4格键值对这些属性进行解码 { if(self == [super init]) { self.show1 = [decoder decodeObjectForKey:kField1Key]; self.show2 = [decoder decodeObjectForKey:kField2Key]; self.show3 = [decoder decodeObjectForKey:kField3Key]; self.show4 = [decoder decodeObjectForKey:kField4Key]; } return self; }
-(id)copyWithZone:(NSZone *)zone//创建一个新的fourline对象,并将所有4格字符串复制到其中 { fourlines *copy = [[[self class] allocWithZone:zone] init]; show1 = [self.show1 copy]; show2 = [self.show2 copy]; show3 = [self.show3 copy]; show4 = [self.show4 copy]; return copy; }
然后打开IP_11persistence2ViewController.h,里面声明四个输出口,这和第一个例子一样,定义两个常量。
#define kFileName @"archive" #define kDataKey @"Data"
打开IP_11persistence2ViewController.m导入fourlines类。
#import "fourlines.h"
修改代码
-(NSString *)dataFilePath//用来返回数据文件的完整路径名 { NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES); NSString *paths = [path objectAtIndex:0]; return [paths stringByAppendingPathComponent:kFileName]; }
-(void)applicationWillTerminate:(NSNotification *)notification//应用程序在退出时调用,将数据保存到数据列表 { fourlines *fourline = [[fourlines alloc] init]; fourline.show1 = show1.text; fourline.show2 = show2.text; fourline.show3 = show3.text; fourline.show4 = show4.text;
NSMutableData *data = [[NSMutableData alloc] init]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; [archiver encodeObject:fourline forKey:kDataKey]; [archiver finishEncoding]; [data writeToFile:[self dataFilePath] atomically:YES]; [fourline release]; [archiver release]; [data release]; }
-(void)viewDidLoad { NSString *filePath = [self dataFilePath];//得到文件路径 if([[NSFileManager defaultManager] fileExistsAtPath:filePath])//如果该文件存在就加载 { NSMutableData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]]; NSKeyedUnarchiver *archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; fourlines *fourline = [archiver decodeObjectForKey:kDataKey]; [archiver finishDecoding];
show1.text = fourline.show1; show2.text = fourline.show2; show3.text = fourline.show3; show4.text = fourline.show4;
[archiver release]; [data release]; } UIApplication *app = [UIApplication sharedApplication]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app]; [super viewDidLoad]; }
对IP_11persistence2ViewController.xib的操作同第一个。
下面来创建最后一个使用SQLite来保存数据。我创建的项目名是IP_11SQLite。
首先导入libsqlite3.lib,这和导入FrameWork一样,在Framework文件夹上面右击,ADD-Existing Files然后选择文件,该文件在/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/usr/lib/libsqlite3.dylib下面。导入后开始修改代码。
打开IP_11SQLiteViewController.h
#import "/usr/include/sqlite3.h" #define kFileName @"data.sqlite3"
增加一个变量:sqlite3 *database;
修改后为:
#import <UIKit/UIKit.h> #import "/usr/include/sqlite3.h" #define kFileName @"data.sqlite3"
@interface IP_11SQLiteViewController : UIViewController { IBOutlet UITextField *show1; IBOutlet UITextField *show2; IBOutlet UITextField *show3; IBOutlet UITextField *show4;
sqlite3 *database; } @property (nonatomic,retain) UITextField *show1; @property (nonatomic,retain) UITextField *show2; @property (nonatomic,retain) UITextField *show3; @property (nonatomic,retain) UITextField *show4; -(NSString *)dataFilePath; -(void)applicationWillTerminate:(NSNotification *)notification; @end
然后打开IP_11SQLiteViewController.m修改代码如下:
-(NSString *)dataFilePath//用来返回数据文件的完整路径名 { NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES); NSString *paths = [path objectAtIndex:0]; return [paths stringByAppendingPathComponent:kFileName]; }
-(void)applicationWillTerminate:(NSNotification *)notification//应用程序在退出时调用,将数据保存到数据列表 { for(int i = 1; i<=4; i++) { NSString *fieldName = [[NSString alloc] initWithFormat:@"show%d",i]; UITextField *field = [self valueForKey:fieldName];//根据每一i的值设定相应textfield [fieldName release];
NSString *update = [[NSString alloc] initWithFormat:@"insert or replace into fields (row,field_data) values (%d,'%@');",field.text];//插入或更新表 char *errorMsg;
if(sqlite3_exec(database,[update UTF8String],NULL,&errorMsg) != SQLITE_OK)//执行插入或更新操作,如果插入或更新失败给出错误信息 { NSAssert1(0,@"Error updating tables: %s",errorMsg); sqlite3_free(errorMsg); } } sqlite3_close(database);//关闭数据库连接 }
-(void)viewDidLoad { if(sqlite3_open([[self dataFilePath] UTF8String],&database) != SQLITE_OK)//打开数据库,如果打开失败给出提示 { sqlite3_close(database); NSAssert(0,@"Failed to open database"); }
char *errorMsg; NSString *createSQL = @"create table if not exists fields (row integer primary key,field_data text);";//创建表 if(sqlite3_exec(database,[createSQL UTF8String],&errorMsg)!=SQLITE_OK)//是否创建成功 { sqlite3_close(database); NSAssert1(0,@"Error creating table: %s",errorMsg); }
NSString *query = @"select row,field_data from fields order by row";//查找表中的数据,行和每一行对应的值 sqlite3_stmt *statement; if(sqlite3_prepare_v2(database,[query UTF8String],-1,&statement,nil) == SQLITE_OK) { while(sqlite3_step(statement) == SQLITE_ROW) { int row = sqlite3_column_int(statement,0); char *rowData = (char *)sqlite3_column_text(statement,1);
NSString *fieldName = [[NSString alloc] initWithFormat:@"show%d",row]; NSString *fieldValue = [[NSString alloc] initWithUTF8String:rowData]; UITextField *field = [self valueForKey:fieldName]; field.text = fieldValue; [fieldName release]; [fieldValue release]; } sqlite3_finalize(statement); }
UIApplication *app = [UIApplication sharedApplication]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app]; [super viewDidLoad]; } 最后就是IP_11SQLiteViewController.xib的修改了,和第一个一样的。
到此三种方法的操作结束了。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|