phone开发基础教程
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属性。这样把该项目下自己创建的类都让其继承该类。
在RootViewController.m中添加代码。 #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这样主视图中的信息按钮就会变成黑色,这样在白色背景下面就会有好的显示效果。 更改info.plist文件,添加图标。 在根目录上面(就是点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; 打开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,'%@');",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/。 。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |