Iphone开发基础教程》第九章 导航控制器和表视图(2009-08-11 12:06:17)
这一章比较庞大,里面的例子也比较多,我看书和实践一共花了我一周的时间,然后自己又摸索构建一个View实现了一点功能,到今天才写这一章的东西,呵呵,晚了点了!
UINavigationController是用于构建分层应用程序的主要工具,它在管理以及换入和换出多个内容视图方面与UITabBarController较为相似,但是主要不同之处在于前者是作为栈来实现的,这让它非常实用处理分层数据。
创建Window-Based Application,我创建的项目名称是IP_09Nav。创建一个新类,UIViewController subclass命名为RootViewController,该类将包含导航控制器的根视图的控制器类。
设置导航控制器。打开IP_09NavAppDelegate.h添加一个输出口。
IBOutlet UINavigationController *navController;//声明一个Navigation输出口
在IP_09NavAppDelegate.m中添加子视图:
[window addSubview:navController.view];//添加Navigation导航模板到window
接下来打开MainWindow.xib,向里面拖入一个Navigation Controller,要拖入nib窗口而不是view窗口。按下control键,并从IP_09Nav App Delegate图标拖入到新的Navigation Controller图标选中navController输出口。下面要将窗口工具栏中间的View Model按钮将nib主窗口改为列表模式。点Navigation Controller前面的小箭头,找到View Controller,然后Apple+4将基类修改为RootViewControoler。
接下来我们要创建一个类让其继承UITableViewController,这样我们做的目的是我们在继承的子类中添加一个UIImage的属性,并且让所有的Nav继承此类,这样所有的Nav也就有了UIImage这样一个属性了。
创建一个新类SecondLViewController。让其继承UITableViewController,给一个UIImage属性。这样把该项目下自己创建的类都让其继承该类。
#import "SecondLevelViewController.h"//导入该类是为了使用rowImage属性 #import "IP_09NavAppDelegate.h"//导入该类是为了使用应用程序委托
-(void)viewDidLoad { self.title = @"Root L";//设置该控制器的标题 NSMutableArray *array = [[NSMutableArray alloc]init];//创建一个可变数组,用来保存每一个二级视图 self.controllers = array; [array release]; [super viewDidLoad]; } #pragma mark Table Date source methods //返回数组的计数,也就是在根视图下面一共有多少二级视图 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.controllers count]; }
//返回单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *RootViewControllerCell = @"RootViewControllerCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RootViewControllerCell]; if(cell == nil) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:RootViewControllerCell]autorelease]; } NSUInteger row = [indexPath row]; SecondLevelViewController *controller = [controllers objectAtIndex:row]; cell.text = controller.title; cell.image = controller.rowImage; return cell; }
#pragma mark table View Delegate Methods //用来显示二级视图后面的箭头 -(UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath { return UITableViewCellAccessoryDisclosureIndicator; }
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath //用户单击每行时调用的方法 { NSUInteger row = [indexPath row];//获取单击时的行 SecondLevelViewController *nextController = [self.controllers objectAtIndex:row];//从对应的行的数组中获取正确的控制器 IP_09NavAppDelegate *delegate = [[UIApplication sharedApplication] delegate];//用应用程序委托来维护导航控制器,使用共享的UIApplication实例获取到该委托的引用 [delegate.navController pushViewController:nextController animated:YES];//使用委托的navController输出口将下一个控制器放到导航控制器中 } 这样弄好以后build and go就可以显示一个空的试图了。
下面添加第一个自控制器:展示按钮试图
创建两个类DisclosureButtonController和DisclosureDetailController前一个类是为了显示二级试图里面的项,后一个主要是和xib文件关联显示详细信息。
打开DisclosureDetailController.h添加两个变量:
IBOutlet UILabel *label;//用户显示的label NSString *message; 在DisclosureDetailController.m中添加viewWillAppear方法。
//此处用viewillAppear方法,而不用viewDidLoad方法是因为viewDidLoad方法只在第一次加载其视图的时候调用。用该方法在每次单击按钮的时候都会被调用 -(void)viewWillAppear:(BOOL)animated { label.text = message; [super viewWillAppear:animated]; }
然后创建一个xib文件,名称为DisclosureDetail.xib然后拖入一个UILabel,调整好大小,让其和DisclosureDetailController类相关联,并且连接好输出口。
下面修改DisclosureButtonController.h。
#import <UIKit/UIKit.h> #import "SecondLevelViewController.h" @class DisclosureDetailController;
@interface DisclosureButtonController : SecondLevelViewController <UITableViewDelegate,UITableViewDataSource> { NSArray *list; DisclosureDetailController *childCntroller; } @property (nonatomic,retain) NSArray *list; @property (nonatomic,retain) DisclosureDetailController *childCntroller; @end
接下来修改DisclosureButtonController.m
#import "IP_09NavAppDelegate.h" #import "DisclosureDetailController.h"
//初始化一个数据源 -(void)viewDidLoad { NSArray *array = [[NSArray alloc]initWithObjects:@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",nil]; self.list = array; [array release]; [super viewDidLoad]; }
#pragma mark Table dataSource methods -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [list count]; }
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *s = @"DisclosureButtonCellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:s]; if(cell == nil) { cell = [[[UITableViewCell alloc]initWithFrame:CGRectZero reuseIdentifier:s]autorelease]; } NSInteger row = [indexPath row]; NSString *rowString = [list objectAtIndex:row]; cell.text = rowString; [rowString release]; return cell; }
#pragma mark Table Delegate methods 委托方法 //返回带展示按钮的行 -(UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath { return UITableViewCellAccessoryDetailDisclosureButton; }
//选中行时调用,给出提示,而不是选中按钮给出提示 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger row = [indexPath row]; NSString *message = [self.list objectAtIndex:row]; UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Show" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; [alert release]; [message release]; }
//点击后面的按钮展示下一级菜单 -(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { if(childCntroller == nil) { childCntroller = [[DisclosureDetailController alloc]initWithNibName:@"DisclosureDetail" bundle:nil]; } childCntroller.title = @"你好!"; NSUInteger row = [indexPath row];//得到上级的行 NSString *selectedMovid = [list objectAtIndex:row];//得到上级的值 NSString *detailMessage = [[NSString alloc] initWithFormat:@"you pressed the disclosure button for %@",selectedMovid]; childCntroller.message = detailMessage; childCntroller.title = selectedMovid; [detailMessage release]; IP_09NavAppDelegate *delegate = [[UIApplication sharedApplication]delegate]; [delegate.navController pushViewController:childCntroller animated:YES]; } 最后在RootViewController中把
#import "DisclosureButtonController.h"
DisclosureButtonController *dbutton = [[DisclosureButtonController alloc]initWithStyle:UITableViewStylePlain]; dbutton.title = @"Disclosure button"; dbutton.rowImage = [UIImage imageNamed:@"disclosureButtonControllerIcon.png"]; [array addObject:dbutton]; [dbutton release];
运行一下看看。
第二个子控制器:校验表(也就是允许用户从列表中选择一个项目)
创建一个新类CheckListController,继承自SecondLevelViewController。限于篇幅有限,代码我就不在这上面添加了,具体代码可以去我CSDN上面下载,代码中有注释。
代码填写好后在RootViewController里面添加一个二级试图,方法和第一个相似。
然后运行。
第三个控制器:表行上的控件
创建一个新类RowControllersController,继承SecondLevelViewController。具体代码下载看吧。
这几个控制器和第一个差不多,步骤都大同小异,想必自己摸索一下就好了。
第四个控制器:可移动的行
这个演示主要是让其行在编辑模式下面可以随心所欲的移动。也是代码操作,步骤入第一个。
第五个控制器:可删除的行(同第四个)
第六个控制器:可便捷的详细窗格
创建数据模型对象。创建一个新类President这个选择模板为NSObject subclass,然后添加代码。导入Presidents.plist文件。
创建控制器。创建两个类PresidentsViewController和PresidentDetailController。具体代码可以去下载,太多了。
最后这个比较麻烦,一定要信息,上面的方法要一点一点搞明白。我最后就是把这个演示用xib实现了一下,用的plist文件也是自己创建的,也可以下载,但是还是有一点问题,有时候会推出,现在还在研究阶段。
最后上几个关于本章的几个图片:
《Iphone开发基础教程》第十章 应用程序设置和用户默认设置
这一章主要介绍的是如何向Iphone的Settings应用程序中添加自己的应用设置,以及如何从应用程序内部访问这些设置。
用户默认设置是应用程序首选项的一部分,由NSUserDefaults类实现,用户保存和获取首选项。与NSDictonary获取数据一样,实用键值读取和保存首选项数据。不同之处是NSUserDefaults数据被持久化到文件系统中,而没有存储在内存中的对象实例中。
Settings应用程序的优势之一是无需为首选项设计用户界面。创建属性列表来定义应用程序的可用设置后,Settings应用程序会自动创建用户界面。但是使用Settings应用程序也有一些限制,当应用程序正在运行时,用户可能需要更改的任何首选项都不应该受到Settings应用程序的限制,因为用户可能被强制退出应用程序以更改这些值。互动式应用程序,通常应该提供首选项视图,使用户更改设置时无需退出应用程序。
下面开始这一章的练习。
创建新的项目,这次使用的是Utility Application模板。我创建的项目名称是:IP_10Seting
这个模板从来没有使用过,首先先来熟悉一下该模板。该模板创建出来的应用程序有一个主视图和一个辅助试图,点击主视图中的信息按钮会进入辅助试图,点击辅助试图中的Done按钮会返回主视图。
在这个项目中,你会发现没有Classes文件夹,因为事先这种类型的应用程序需要许多文件,该模板已经将这些文件组织到一些分组中,展开文件夹Main View、Flipside View和Application Controllers,然后将Resources也打开。然后就会看到在每一个文件夹下面会自动对应几个类文件。组成主视图的所有类,包括试图控制器和一个UIView子类,都包含在Main View文件夹中。事先flipside试图所需要的源代码文件都包含在Flipside View文件夹中,最后应用程序委托和控制器类都包含在Application Controllers文件夹中。
打开MainWindow.xib,将主视图更改为列表模式,点击Root View Controller,View,light info button并在此上apple+4,在type中选择info dark这样主视图中的信息按钮就会变成黑色,这样在白色背景下面就会有好的显示效果。
在根目录上面(就是点IP_10Seting)创建新项目,选择Settings Bundle,创建一个新的Bundle(用默认的名字)。
创建属性列表时要用固定的模式,在创建的Bundle中已经存在了一个Root.plist文件,我们对这个文件进行修改就好了。
打开Root.plist文件,在最上面的Title里修改你Setting的名字。SettingsTable先不用管。在PreferenceSpecifiers项下,有许都的项目,删除2,3,4项。然后展开1,修改Title,这个Title会显示在Settings里面。然后在Item1下面在添加一项,默认是string类型,修改为Dictionary,然后向里面添加5项。Type/PSTextFieldSpecifier,Title/Username,Key/username,AutocapitalizetionType/None,AutocorrectionType/No。PSTextFieldSpecifier说明我们希望在该文本字段中编辑此设置。AutocapitalizetionType指的是该文本字段不要尝试自动大写用户输入的内容。AutocorrectionType这个是告诉Settings不需要自动更正输入到该文本中的值。
到此都可以运行一下看看结果了。
下面添加安全字段设置。
添加一新项,简单的方法就是直接复制item 2然后粘贴就好了,修改item 3中的项。
Type/PSTextFieldSpecifier,Title/Pasword,Key/pasword,AutocapitalizetionType/None,AutocorrectionType/No,IsSecure/Boolean类选中,这样输入的密码就要被点所代替。
Type/PSMultiValueSpecifier,Title/Protocol,Key/protocol,添加两个Array类型的值。Titles和Values,其中Titles是显示在Settings中的值,而values是显示的值对应的一个值。DefaultValue/1,这个是启动的时候默认的值。
Type/PSToggleSwitchSpecifier,Title/Warp Drive,Key/warp,Truue/Engaged,Falsue/Disabled,DefaultValue/Engaged。
添加滑块设置。在添加滑块设置前,让我们再创建一个分组。很简单就是复制item 1,然后粘贴就好了。(这个例子中的粘贴都是选中最后行然后粘贴,让粘贴的行成为最后的行)
修改键值。
Type/PSSliderSpecifier,Key/warpfactor,DefaultValue/5,MinimumValue/0,MaximumValue/10,MinimumValueImage/rabbit.png,MaximumValueImage/turtle.png,从前到后以此为类型,key值,默认值,最小值,最多值,slider左边显示的图标,slider右边显示的图标。
所谓的添加子视图,其实就是再添加一个plist文件罢了。在复制,粘贴一行,修改键值。
Type/PSChildPaneSpecifier,Title/More Settings,File/More这个就是新的plist文件。
创建新的plist文件也有一个诀窍,我们可以复制一个Root.plist文件,粘贴然后修改名字,修改里面的项就Ok了。但是这里的复制和粘贴不能在Xcode里面完成,我们必须找到项目所在的文件夹,找到Setting.bundle然后点右键,让其显示文件夹里面的内容,在这里面进行复制粘贴操作才可。
到此该bundle创建完成,下面的就是我们怎么读出来了。
读取应用程序设置。
读取操作主要是应用NSUserDefaults类进行。
首先打开MainViewController.h。添加常量和变量。
//这里面定义的常量对应Setting.bundle里面Root.plist里面每一项的key值 #define kUsernameKey @"username" #define kSwitch @"warp" #define kSlider @"warpfactor" #define kPasword @"pasword" #define kProtocol @"protocol"
#define kSecondname @"secondname" #define kUseraddress @"useraddress" #define kUserBirth @"userbirth" #define kUserPhone @"userphone" #define kSecondProtocol @"secondprotocol"
IBOutlet UILabel *usernameLabel; IBOutlet UILabel *paswordLabel; IBOutlet UILabel *protocolLabel; IBOutlet UILabel *secondname; IBOutlet UILabel *useraddress; IBOutlet UILabel *userbirth; IBOutlet UILabel *userphone; IBOutlet UILabel *secondprotocol; IBOutlet UILabel *switchStats; IBOutlet UILabel *sliderValue;
然后打开MainViewController.m添加三个方法。
//这个新的方法仅用于抓取标准用户默认设置,并使用我们输入到属性文件中的键值,将所有标签的文本属性设置为用户默认设置中的适当对象 -(void)refreshFields { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; usernameLabel.text = [defaults objectForKey:kUsernameKey]; paswordLabel.text = [defaults objectForKey:kPasword]; protocolLabel.text = [defaults objectForKey:kProtocol]; secondname.text = [defaults objectForKey:kSecondname]; useraddress.text = [defaults objectForKey:kUseraddress]; userbirth.text = [defaults objectForKey:kUserBirth]; userphone.text = [defaults objectForKey:kUserPhone]; secondprotocol.text = [defaults objectForKey:kSecondProtocol]; switchStats.text = [defaults objectForKey:kSwitch]; sliderValue.text = [[defaults objectForKey:kSlider]stringValue]; }
//在viewDidLoad和viewDidAppear中调用refreshfields方法,使得在视图载入时显示的字段将设置为合适的首选项值,然后在视图更新 //首选项时,显示的字段将被刷新 -(void)viewDidAppear:(BOOL)animated { [self refreshFields]; [super viewDidAppear:animated]; }
- (void)viewDidLoad { [self refreshFields]; }
当然了,需要打开MainView.xib,向里面拖入适当的UILabel并且和刚才定义的变量进行关联。
这样主视图的读取已经结束。
现在添加辅助视图,在辅助试图我们添加一个switch和一个slider用来读取应用程序设置中的值。
打开FlipsideViewController.h,添加两个输出口。
IBOutlet UISwitch *switchshow; IBOutlet UiSlider *slidershow;
打开FlipsideViewController.m,首先引入MainViewController。
#import "MainViewController.h"
- (void)viewDidLoad { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; switchshow.on = ([[defaults objectForKey:kSwitch]isEqualToString:@"Engaged"])?YES:NO; slidershow.value = [defaults floatForKey:kSlider]; }
//重写viewWillDisappear方法,以便在主视图再次显示之前,将控件的值填充到用户默认设置中。 - (void)viewWillDisappear:(BOOL)animated { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *prefValue = (switchshow.on)? @"Engaged": @"Disabled"; [defaults setObject:prefValue forKey:kSwitch]; [defaults setFloat:slidershow.value forKey:kSlider]; [super viewWillDisappear:animated]; }
好了,释放资源,build and go运行吧,看看结果。
到此结束,不是很难,这一章就半天就可以搞定。
源代码在我的csdn上面有,需要的可以去下载,下载地址http://hanyegudeng.download.csdn.net/
《Iphone开发基础教程》第十一章 基本数据持久
以前我们也用到过读取数据,但是没有一个应用程序是将其数据永久性存储,也就是在应用重启,机器重启后数据不会丢失,和上一次最后的数据一致。这章一共定义了三种保持数据的方法,第一种:实用属性列表,第二种:对象归档,第三种:使用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;
-(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"
修改后为:
#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,'%@');",i,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的修改了,和第一个一样的。
到此三种方法的操作结束了。
源代码在我的csdn上面有,需要的可以去下载,下载地址http://hanyegudeng.download.csdn.net/。
。
原文链接:https://www.f2er.com/sqlite/202973.html