通过segue切换视图控制器
在使用storyboard开发iOS应用时,从一个视图控制器的视图中点击一个按钮跳转到另外一个视图控制器的视图的操作开始使用segue实现。storyboard较之以前的nib最大的优点就是很直观地、图形化地展示各个视图控制器之间的关系。这个关系就是通过segue来实现。
通过segue,可以将一个视图控制器的数据传输到跳转到的另一个视图控制器上,再通过delegate是释放这个视图控制器并将新的数据传回来。这个segue的类型一般设置为modal。
(miki西游 @mikixiyou 原文链接: http://mikixiyou.iteye.com/blog/1751623
)
第一个视图控制器LoginViewController,用来显示登录窗口。它的视图中有两个textfield,用于录入用户名和密码,一个button,点击该button,通过拖到目标视图控制器上的segue来实现视图切换。
它的代码如下:
#import <UIKit/UIKit.h> @interface LoginViewController : UIViewController <UITextFieldDelegate> @property (weak, nonatomic) IBOutlet UITextField *usernameInput; @property (weak, nonatomic) IBOutlet UITextField *passwdInput; @end #import "LoginViewController.h" #import "LogoffViewController.h" @interface LoginViewController () <LogoffViewControllerDelegate> @end @implementation LoginViewController @synthesize usernameInput=_usernameInput,passwdInput=_passwdInput; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"LogoffView"]) { LogoffViewController * logoffController=[segue destinationViewController]; logoffController.u01=self.usernameInput.text; logoffController.u02=self.passwdInput.text; logoffController.delegate=self; } } -(void)logoffViewControllerDone:(LogoffViewController *)controller username:(NSString *)username passwd:(NSString *)passwd { [self dismissViewControllerAnimated:YES completion:NULL]; NSLog(@"username is %@",username); } - (BOOL)textFieldShouldReturn:(UITextField *)textField { if ((textField == self.usernameInput) || (textField == self.passwdInput)) { [textField resignFirstResponder]; } return YES; } @end
在prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender方法中,实现目标视图控制器属性的设置,实际上是将数据传输到目标视图控制器上,并设置目标视图控制器的委托为自己。
这样通过这个委托可以再切换回来。
在logoffViewControllerDone:(LogoffViewController *)controller username:(NSString *)username passwd:(NSString *)passwd方法中,实现目标控制器的委托的方法。
它会被目标视图控制器调用,将目标视图控制器的数据传过来,并释放目标视图控制器。
第二个视图控制器LogoffViewController,用来显示前一个视图控制器的切换窗口,有两个lable用来显示传输过来的用户名和密码信息,一个button用来释放自己,并回到前一个视图控制器窗口。
#import <UIKit/UIKit.h> @protocol LogoffViewControllerDelegate; @interface LogoffViewController : UIViewController @property (strong,nonatomic) NSString *u01,*u02; @property (weak, nonatomic) IBOutlet UILabel *username; @property (weak, nonatomic) IBOutlet UILabel *passwd; @property (weak,nonatomic) id <LogoffViewControllerDelegate> delegate; - (IBAction)logOff:(id)sender; @end @protocol LogoffViewControllerDelegate <NSObject> -(void)logoffViewControllerDone:(LogoffViewController *)controller username:(NSString *)username passwd:(NSString *)passwd; @end #import "LogoffViewController.h" @implementation LogoffViewController @synthesize u01=_u01,u02=_u02; @synthesize delegate=_delegate; @synthesize username=_username,passwd=_passwd; - (void)viewDidLoad { [super viewDidLoad]; self.username.text=[NSString stringWithFormat:@"username is %@", self.u01]; self.passwd.text=self.u02; } - (IBAction)logOff:(id)sender { [[self delegate] logoffViewControllerDone:self username:self.username.text passwd:self.passwd.text]; } @end
在接口定义中,定义有一个delegate对象,这是用来和源视图控制器交互的。delegate实现了两个对象在松耦合的情况下进行交互。
在方法实现中,增加viewDidLoad方法的功能,显示在源视图控制器中在prepareForSegue:sender:方法里已经设置好属性u01/u02的值。viewDidLoad方法是视图控制器加载视图时执行的方法。一些界面设置工作都在这里完成。
方法logOff:用来实现窗口中logoff按钮的目标的动作。该方法实际上是调用的它的委托也就是源视图控制器中的logoffViewControllerDone:(LogoffViewController *)controller username:(NSString *)username passwd:(NSString *)passwd方法。
在写个程序时,遇到NSUnknownKeyException错误,主要信息如下:
2012-12-20 21:17:08.646 BirdWatching[1609:11303] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<LogoffViewController 0x75efa70> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key userName.'
这个错误发生在prepareForSegue:sender:方法执行结束时。
显然在LogoffViewController视图控制器上没有userName这个属性。这个属性是我之前定义的,后来删除掉了。
在storyboard中,还有连接这个userName属性的outlet。
这个问题在反复删除时会出现,不知道算不算是storyboard的bug。对于我这个初学者而言,折腾了很久。但也学会了XCODE的debug功能,它其实也就是个gdb调试工具。
这个借segue切换视图控制器的操作过程,和UIViewController中的方法presentViewController:animated:completion:和dismissViewControllerAnimated:completion:很类似。怀疑它的内部实现也是用这两个方法来实现的。